layerscape: remove support for kernel 4.14
[openwrt/staging/dedeckeh.git] / target / linux / layerscape / patches-4.14 / 709-mdio-phy-support-layerscape.patch
diff --git a/target/linux/layerscape/patches-4.14/709-mdio-phy-support-layerscape.patch b/target/linux/layerscape/patches-4.14/709-mdio-phy-support-layerscape.patch
deleted file mode 100644 (file)
index 17fe50c..0000000
+++ /dev/null
@@ -1,3729 +0,0 @@
-From c24cbb648c5bde8312dbd5498a4b8c12b2692205 Mon Sep 17 00:00:00 2001
-From: Biwen Li <biwen.li@nxp.com>
-Date: Wed, 17 Apr 2019 18:58:45 +0800
-Subject: [PATCH] mdio-phy: support layerscape
-
-This is an integrated patch of mdio-phy for layerscape
-
-Signed-off-by: Bhaskar Upadhaya <Bhaskar.Upadhaya@nxp.com>
-Signed-off-by: Biwen Li <biwen.li@nxp.com>
-Signed-off-by: Camelia Groza <camelia.groza@nxp.com>
-Signed-off-by: Constantin Tudor <constantin.tudor@nxp.com>
-Signed-off-by: costi <constantin.tudor@freescale.com>
-Signed-off-by: Florin Chiculita <florinlaurentiu.chiculita@nxp.com>
-Signed-off-by: Florinel Iordache <florinel.iordache@nxp.com>
-Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
-Signed-off-by: Ioana Radulescu <ruxandra.radulescu@nxp.com>
-Signed-off-by: Madalin Bucur <madalin.bucur@freescale.com>
-Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
-Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
-Signed-off-by: Valentin Catalin Neacsu <valentin-catalin.neacsu@nxp.com>
-Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
----
- drivers/net/phy/Kconfig                    |   33 +
- drivers/net/phy/Makefile                   |    5 +
- drivers/net/phy/aquantia.c                 |  286 ++++-
- drivers/net/phy/at803x.c                   |   21 +
- drivers/net/phy/fsl_backplane.c            | 1780 ++++++++++++++++++++++++++++
- drivers/net/phy/fsl_backplane.h            |   41 +
- drivers/net/phy/fsl_backplane_serdes_10g.c |  281 +++++
- drivers/net/phy/fsl_backplane_serdes_28g.c |  336 ++++++
- drivers/net/phy/inphi.c                    |  594 ++++++++++
- drivers/net/phy/mdio-mux-multiplexer.c     |  122 ++
- drivers/net/phy/swphy.c                    |    1 +
- include/linux/phy.h                        |    3 +
- 12 files changed, 3484 insertions(+), 19 deletions(-)
- create mode 100644 drivers/net/phy/fsl_backplane.c
- create mode 100644 drivers/net/phy/fsl_backplane.h
- create mode 100644 drivers/net/phy/fsl_backplane_serdes_10g.c
- create mode 100644 drivers/net/phy/fsl_backplane_serdes_28g.c
- create mode 100644 drivers/net/phy/inphi.c
- create mode 100644 drivers/net/phy/mdio-mux-multiplexer.c
-
---- a/drivers/net/phy/Kconfig
-+++ b/drivers/net/phy/Kconfig
-@@ -87,9 +87,27 @@ config MDIO_BUS_MUX_MMIOREG
-         Currently, only 8/16/32 bits registers are supported.
-+config MDIO_BUS_MUX_MULTIPLEXER
-+      tristate "MDIO bus multiplexer using kernel multiplexer subsystem"
-+      depends on OF
-+      select MULTIPLEXER
-+      select MDIO_BUS_MUX
-+      help
-+        This module provides a driver for MDIO bus multiplexer
-+        that is controlled via the kernel multiplexer subsystem. The
-+        bus multiplexer connects one of several child MDIO busses to
-+        a parent bus.  Child bus selection is under the control of
-+        the kernel multiplexer subsystem.
-+
- config MDIO_CAVIUM
-       tristate
-+config MDIO_FSL_BACKPLANE
-+      tristate "Support for backplane on Freescale XFI interface"
-+      depends on OF_MDIO
-+      help
-+        This module provides a driver for Freescale XFI's backplane.
-+
- config MDIO_GPIO
-       tristate "GPIO lib-based bitbanged MDIO buses"
-       depends on MDIO_BITBANG && GPIOLIB
-@@ -303,6 +321,16 @@ config AT803X_PHY
-       ---help---
-         Currently supports the AT8030 and AT8035 model
-+config AT803X_PHY_SMART_EEE
-+      depends on AT803X_PHY
-+      default n
-+      tristate "SmartEEE feature for AT803X PHYs"
-+      ---help---
-+        Enables the Atheros SmartEEE feature (not IEEE 802.3az). When 2 PHYs
-+        which support this feature are connected back-to-back, they may
-+        negotiate a low-power sleep mode autonomously, without the Ethernet
-+        controller's knowledge.  May cause packet loss.
-+
- config BCM63XX_PHY
-       tristate "Broadcom 63xx SOCs internal PHY"
-       depends on BCM63XX
-@@ -385,6 +413,11 @@ config ICPLUS_PHY
-       ---help---
-         Currently supports the IP175C and IP1001 PHYs.
-+config INPHI_PHY
-+      tristate "Inphi CDR 10G/25G Ethernet PHY"
-+      ---help---
-+        Currently supports the IN112525_S03 part @ 25G
-+
- config INTEL_XWAY_PHY
-       tristate "Intel XWAY PHYs"
-       ---help---
---- a/drivers/net/phy/Makefile
-+++ b/drivers/net/phy/Makefile
-@@ -44,7 +44,11 @@ obj-$(CONFIG_MDIO_BUS_MUX)  += mdio-mux.o
- obj-$(CONFIG_MDIO_BUS_MUX_BCM_IPROC)  += mdio-mux-bcm-iproc.o
- obj-$(CONFIG_MDIO_BUS_MUX_GPIO)       += mdio-mux-gpio.o
- obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o
-+obj-$(CONFIG_MDIO_BUS_MUX_MULTIPLEXER) += mdio-mux-multiplexer.o
- obj-$(CONFIG_MDIO_CAVIUM)     += mdio-cavium.o
-+obj-$(CONFIG_MDIO_FSL_BACKPLANE) += fsl_backplane.o
-+obj-$(CONFIG_MDIO_FSL_BACKPLANE) += fsl_backplane_serdes_10g.o
-+obj-$(CONFIG_MDIO_FSL_BACKPLANE) += fsl_backplane_serdes_28g.o
- obj-$(CONFIG_MDIO_GPIO)               += mdio-gpio.o
- obj-$(CONFIG_MDIO_HISI_FEMAC) += mdio-hisi-femac.o
- obj-$(CONFIG_MDIO_I2C)                += mdio-i2c.o
-@@ -75,6 +79,7 @@ obj-$(CONFIG_DP83848_PHY)    += dp83848.o
- obj-$(CONFIG_DP83867_PHY)     += dp83867.o
- obj-$(CONFIG_FIXED_PHY)               += fixed_phy.o
- obj-$(CONFIG_ICPLUS_PHY)      += icplus.o
-+obj-$(CONFIG_INPHI_PHY)       += inphi.o
- obj-$(CONFIG_INTEL_XWAY_PHY)  += intel-xway.o
- obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
- obj-$(CONFIG_LXT_PHY)         += lxt.o
---- a/drivers/net/phy/aquantia.c
-+++ b/drivers/net/phy/aquantia.c
-@@ -4,6 +4,7 @@
-  * Author: Shaohui Xie <Shaohui.Xie@freescale.com>
-  *
-  * Copyright 2015 Freescale Semiconductor, Inc.
-+ * Copyright 2018 NXP
-  *
-  * This file is licensed under the terms of the GNU General Public License
-  * version 2.  This program is licensed "as is" without any warranty of any
-@@ -27,15 +28,174 @@
- #define PHY_AQUANTIA_FEATURES (SUPPORTED_10000baseT_Full | \
-                                SUPPORTED_1000baseT_Full | \
-+                               SUPPORTED_2500baseX_Full | \
-                                SUPPORTED_100baseT_Full | \
-                                PHY_DEFAULT_FEATURES)
-+#define MDIO_PMA_CTRL1_AQ_SPEED10     0
-+#define MDIO_PMA_CTRL1_AQ_SPEED2500   0x2058
-+#define MDIO_PMA_CTRL1_AQ_SPEED5000   0x205c
-+#define MDIO_PMA_CTRL2_AQ_2500BT       0x30
-+#define MDIO_PMA_CTRL2_AQ_5000BT       0x31
-+#define MDIO_PMA_CTRL2_AQ_TYPE_MASK    0x3F
-+
-+#define MDIO_AN_VENDOR_PROV_CTRL       0xc400
-+#define MDIO_AN_RECV_LP_STATUS         0xe820
-+
-+static int aquantia_write_reg(struct phy_device *phydev, int devad,
-+                            u32 regnum, u16 val)
-+{
-+      u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
-+
-+      return mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, addr, val);
-+}
-+
-+static int aquantia_read_reg(struct phy_device *phydev, int devad, u32 regnum)
-+{
-+      u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
-+
-+      return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
-+}
-+
-+static int aquantia_pma_setup_forced(struct phy_device *phydev)
-+{
-+      int ctrl1, ctrl2, ret;
-+
-+      /* Half duplex is not supported */
-+      if (phydev->duplex != DUPLEX_FULL)
-+              return -EINVAL;
-+
-+      ctrl1 = aquantia_read_reg(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
-+      if (ctrl1 < 0)
-+              return ctrl1;
-+
-+      ctrl2 = aquantia_read_reg(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2);
-+      if (ctrl2 < 0)
-+              return ctrl2;
-+
-+      ctrl1 &= ~MDIO_CTRL1_SPEEDSEL;
-+      ctrl2 &= ~(MDIO_PMA_CTRL2_AQ_TYPE_MASK);
-+
-+      switch (phydev->speed) {
-+      case SPEED_10:
-+              ctrl2 |= MDIO_PMA_CTRL2_10BT;
-+              break;
-+      case SPEED_100:
-+              ctrl1 |= MDIO_PMA_CTRL1_SPEED100;
-+              ctrl2 |= MDIO_PMA_CTRL2_100BTX;
-+              break;
-+      case SPEED_1000:
-+              ctrl1 |= MDIO_PMA_CTRL1_SPEED1000;
-+              /* Assume 1000base-T */
-+              ctrl2 |= MDIO_PMA_CTRL2_1000BT;
-+              break;
-+      case SPEED_10000:
-+              ctrl1 |= MDIO_CTRL1_SPEED10G;
-+              /* Assume 10Gbase-T */
-+              ctrl2 |= MDIO_PMA_CTRL2_10GBT;
-+              break;
-+      case SPEED_2500:
-+              ctrl1 |= MDIO_PMA_CTRL1_AQ_SPEED2500;
-+              ctrl2 |= MDIO_PMA_CTRL2_AQ_2500BT;
-+              break;
-+      case SPEED_5000:
-+              ctrl1 |= MDIO_PMA_CTRL1_AQ_SPEED5000;
-+              ctrl2 |= MDIO_PMA_CTRL2_AQ_5000BT;
-+              break;
-+      default:
-+              return -EINVAL;
-+      }
-+
-+      ret = aquantia_write_reg(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1, ctrl1);
-+      if (ret < 0)
-+              return ret;
-+
-+      return aquantia_write_reg(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL2, ctrl2);
-+}
-+
-+static int aquantia_aneg(struct phy_device *phydev, bool control)
-+{
-+      int reg = aquantia_read_reg(phydev, MDIO_MMD_AN, MDIO_CTRL1);
-+
-+      if (reg < 0)
-+              return reg;
-+
-+      if (control)
-+              reg |= MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART;
-+      else
-+              reg &= ~(MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
-+
-+      return aquantia_write_reg(phydev, MDIO_MMD_AN, MDIO_CTRL1, reg);
-+}
-+
-+static int aquantia_config_advert(struct phy_device *phydev)
-+{
-+      u32 advertise;
-+      int oldadv, adv, oldadv1, adv1;
-+      int err, changed = 0;
-+
-+      /* Only allow advertising what this PHY supports */
-+      phydev->advertising &= phydev->supported;
-+      advertise = phydev->advertising;
-+
-+      /* Setup standard advertisement */
-+      oldadv = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                                 MDIO_AN_10GBT_CTRL);
-+      if (oldadv < 0)
-+              return oldadv;
-+
-+      /* Aquantia vendor specific advertisments */
-+      oldadv1 = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                                  MDIO_AN_VENDOR_PROV_CTRL);
-+      if (oldadv1 < 0)
-+              return oldadv1;
-+
-+      adv  = 0;
-+      adv1 = 0;
-+
-+      /*100BaseT_full is supported by default*/
-+
-+      if (advertise & ADVERTISED_1000baseT_Full)
-+              adv1 |= 0x8000;
-+      if (advertise & ADVERTISED_10000baseT_Full)
-+              adv |= 0x1000;
-+      if (advertise &  ADVERTISED_2500baseX_Full)
-+              adv1 |= 0x400;
-+
-+      if (adv != oldadv) {
-+              err = aquantia_write_reg(phydev, MDIO_MMD_AN,
-+                                       MDIO_AN_10GBT_CTRL, adv);
-+              if (err < 0)
-+                      return err;
-+              changed = 1;
-+      }
-+      if (adv1 != oldadv1) {
-+              err = aquantia_write_reg(phydev, MDIO_MMD_AN,
-+                                       MDIO_AN_VENDOR_PROV_CTRL, adv1);
-+              if (err < 0)
-+                      return err;
-+              changed = 1;
-+      }
-+
-+      return changed;
-+}
-+
- static int aquantia_config_aneg(struct phy_device *phydev)
- {
-+      int ret = 0;
-+
-       phydev->supported = PHY_AQUANTIA_FEATURES;
--      phydev->advertising = phydev->supported;
-+      if (phydev->autoneg == AUTONEG_DISABLE) {
-+              aquantia_pma_setup_forced(phydev);
-+              return aquantia_aneg(phydev, false);
-+      }
--      return 0;
-+      ret = aquantia_config_advert(phydev);
-+      if (ret > 0)
-+              /* restart autoneg */
-+              return aquantia_aneg(phydev, true);
-+
-+      return ret;
- }
- static int aquantia_aneg_done(struct phy_device *phydev)
-@@ -51,25 +211,26 @@ static int aquantia_config_intr(struct p
-       int err;
-       if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
--              err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1);
-+              err = aquantia_write_reg(phydev, MDIO_MMD_AN, 0xd401, 1);
-               if (err < 0)
-                       return err;
--              err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1);
-+              err = aquantia_write_reg(phydev, MDIO_MMD_VEND1, 0xff00, 1);
-               if (err < 0)
-                       return err;
--              err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001);
-+              err = aquantia_write_reg(phydev, MDIO_MMD_VEND1,
-+                                       0xff01, 0x1001);
-       } else {
--              err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0);
-+              err = aquantia_write_reg(phydev, MDIO_MMD_AN, 0xd401, 0);
-               if (err < 0)
-                       return err;
--              err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0);
-+              err = aquantia_write_reg(phydev, MDIO_MMD_VEND1, 0xff00, 0);
-               if (err < 0)
-                       return err;
--              err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0);
-+              err = aquantia_write_reg(phydev, MDIO_MMD_VEND1, 0xff01, 0);
-       }
-       return err;
-@@ -79,42 +240,129 @@ static int aquantia_ack_interrupt(struct
- {
-       int reg;
--      reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01);
-+      reg = aquantia_read_reg(phydev, MDIO_MMD_AN, 0xcc01);
-       return (reg < 0) ? reg : 0;
- }
-+static int aquantia_read_advert(struct phy_device *phydev)
-+{
-+      int adv, adv1;
-+
-+      /* Setup standard advertisement */
-+      adv = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                              MDIO_AN_10GBT_CTRL);
-+
-+      /* Aquantia vendor specific advertisments */
-+      adv1 = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                               MDIO_AN_VENDOR_PROV_CTRL);
-+
-+      /*100BaseT_full is supported by default*/
-+      phydev->advertising |= ADVERTISED_100baseT_Full;
-+
-+      if (adv & 0x1000)
-+              phydev->advertising |= ADVERTISED_10000baseT_Full;
-+      else
-+              phydev->advertising &= ~ADVERTISED_10000baseT_Full;
-+      if (adv1 & 0x8000)
-+              phydev->advertising |= ADVERTISED_1000baseT_Full;
-+      else
-+              phydev->advertising &= ~ADVERTISED_1000baseT_Full;
-+      if (adv1 & 0x400)
-+              phydev->advertising |= ADVERTISED_2500baseX_Full;
-+      else
-+              phydev->advertising &= ~ADVERTISED_2500baseX_Full;
-+      return 0;
-+}
-+
-+static int aquantia_read_lp_advert(struct phy_device *phydev)
-+{
-+      int adv, adv1;
-+
-+      /* Read standard link partner advertisement */
-+      adv = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                              MDIO_STAT1);
-+
-+      if (adv & 0x1)
-+              phydev->lp_advertising |= ADVERTISED_Autoneg |
-+                                        ADVERTISED_100baseT_Full;
-+      else
-+              phydev->lp_advertising &= ~(ADVERTISED_Autoneg |
-+                                          ADVERTISED_100baseT_Full);
-+
-+      /* Read standard link partner advertisement */
-+      adv = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                              MDIO_AN_10GBT_STAT);
-+
-+      /* Aquantia link partner advertisments */
-+      adv1 = aquantia_read_reg(phydev, MDIO_MMD_AN,
-+                               MDIO_AN_RECV_LP_STATUS);
-+
-+      if (adv & 0x800)
-+              phydev->lp_advertising |= ADVERTISED_10000baseT_Full;
-+      else
-+              phydev->lp_advertising &= ~ADVERTISED_10000baseT_Full;
-+      if (adv1 & 0x8000)
-+              phydev->lp_advertising |= ADVERTISED_1000baseT_Full;
-+      else
-+              phydev->lp_advertising &= ~ADVERTISED_1000baseT_Full;
-+      if (adv1 & 0x400)
-+              phydev->lp_advertising |= ADVERTISED_2500baseX_Full;
-+      else
-+              phydev->lp_advertising &= ~ADVERTISED_2500baseX_Full;
-+
-+      return 0;
-+}
-+
- static int aquantia_read_status(struct phy_device *phydev)
- {
-       int reg;
--      reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
--      reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
-+      /* Read the link status twice; the bit is latching low */
-+      reg = aquantia_read_reg(phydev, MDIO_MMD_AN, MDIO_STAT1);
-+      reg = aquantia_read_reg(phydev, MDIO_MMD_AN, MDIO_STAT1);
-+
-       if (reg & MDIO_STAT1_LSTATUS)
-               phydev->link = 1;
-       else
-               phydev->link = 0;
--      reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
-       mdelay(10);
--      reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
-+      reg = aquantia_read_reg(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1);
-+
-+      if ((reg & MDIO_CTRL1_SPEEDSELEXT) == MDIO_CTRL1_SPEEDSELEXT)
-+              reg &= MDIO_CTRL1_SPEEDSEL;
-+      else
-+              reg &= MDIO_CTRL1_SPEEDSELEXT;
-       switch (reg) {
--      case 0x9:
-+      case MDIO_PMA_CTRL1_AQ_SPEED5000:
-+              phydev->speed = SPEED_5000;
-+              break;
-+      case MDIO_PMA_CTRL1_AQ_SPEED2500:
-               phydev->speed = SPEED_2500;
-               break;
--      case 0x5:
--              phydev->speed = SPEED_1000;
-+      case MDIO_PMA_CTRL1_AQ_SPEED10:
-+              phydev->speed = SPEED_10;
-               break;
--      case 0x3:
-+      case MDIO_PMA_CTRL1_SPEED100:
-               phydev->speed = SPEED_100;
-               break;
--      case 0x7:
--      default:
-+      case MDIO_PMA_CTRL1_SPEED1000:
-+              phydev->speed = SPEED_1000;
-+              break;
-+      case MDIO_CTRL1_SPEED10G:
-               phydev->speed = SPEED_10000;
-               break;
-+      default:
-+              phydev->speed = SPEED_UNKNOWN;
-+              break;
-       }
-+
-       phydev->duplex = DUPLEX_FULL;
-+      aquantia_read_advert(phydev);
-+      aquantia_read_lp_advert(phydev);
-+
-       return 0;
- }
---- a/drivers/net/phy/at803x.c
-+++ b/drivers/net/phy/at803x.c
-@@ -68,6 +68,8 @@
- #define AT803X_DEBUG_REG_5                    0x05
- #define AT803X_DEBUG_TX_CLK_DLY_EN            BIT(8)
-+#define AT803X_LPI_EN                         BIT(8)
-+
- #define ATH8030_PHY_ID 0x004dd076
- #define ATH8031_PHY_ID 0x004dd074
- #define ATH8032_PHY_ID 0x004dd023
-@@ -290,6 +292,19 @@ static void at803x_disable_smarteee(stru
-       phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
- }
-+static void at803x_enable_smart_eee(struct phy_device *phydev, int on)
-+{
-+      int value;
-+
-+      /* 5.1.11 Smart_eee control3 */
-+      value = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x805D);
-+      if (on)
-+              value |= AT803X_LPI_EN;
-+      else
-+              value &= ~AT803X_LPI_EN;
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, 0x805D, value);
-+}
-+
- static int at803x_config_init(struct phy_device *phydev)
- {
-       struct at803x_platform_data *pdata;
-@@ -320,6 +335,12 @@ static int at803x_config_init(struct phy
-       if (ret < 0)
-               return ret;
-+#ifdef CONFIG_AT803X_PHY_SMART_EEE
-+      at803x_enable_smart_eee(phydev, 1);
-+#else
-+      at803x_enable_smart_eee(phydev, 0);
-+#endif
-+
-       if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
-                       phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
-               ret = at803x_enable_rx_delay(phydev);
---- /dev/null
-+++ b/drivers/net/phy/fsl_backplane.c
-@@ -0,0 +1,1780 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ *  DPAA backplane driver.
-+ *   Author: Shaohui Xie <Shaohui.Xie@freescale.com>
-+ *           Florinel Iordache <florinel.iordache@nxp.com>
-+ *
-+ * Copyright 2015 Freescale Semiconductor, Inc.
-+ * Copyright 2018 NXP
-+ *
-+ * Licensed under the GPL-2 or later.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/mii.h>
-+#include <linux/mdio.h>
-+#include <linux/ethtool.h>
-+#include <linux/phy.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_net.h>
-+#include <linux/of_address.h>
-+#include <linux/of_platform.h>
-+#include <linux/timer.h>
-+#include <linux/delay.h>
-+#include <linux/workqueue.h>
-+#include <linux/netdevice.h>
-+
-+#include "fsl_backplane.h"
-+
-+
-+/* PCS Device Identifier */
-+#define PCS_PHY_DEVICE_ID                     0x0083e400
-+#define PCS_PHY_DEVICE_ID_MASK                0xffffffff
-+
-+/* 10G Long cables setup: 1 m to 2 m cables */
-+#define RATIO_PREQ_10G                                0x3
-+#define RATIO_PST1Q_10G                               0xd
-+#define RATIO_EQ_10G                          0x20
-+
-+/* 10G Short cables setup: up to 30 cm cable */
-+//#define RATIO_PREQ_10G                              0x3
-+//#define RATIO_PST1Q_10G                             0xa
-+//#define RATIO_EQ_10G                                0x29
-+
-+/* 40G Long cables setup: 1 m to 2 m cables */
-+#define RATIO_PREQ_40G                                0x2
-+#define RATIO_PST1Q_40G                               0xd
-+#define RATIO_EQ_40G                          0x20
-+
-+/* 40G Short cables setup: up to 30 cm cable */
-+//#define RATIO_PREQ_40G                              0x1
-+//#define RATIO_PST1Q_40G                             0x3
-+//#define RATIO_EQ_40G                                0x29
-+
-+/* LX2 2x40G default RCW setup */
-+//#define RATIO_PREQ_40G                              0x0
-+//#define RATIO_PST1Q_40G                             0x3
-+//#define RATIO_EQ_40G                                0x30
-+
-+/* Max/Min coefficient values */
-+#define PRE_COE_MAX                                   0x0
-+#define PRE_COE_MIN                                   0x8
-+#define POST_COE_MAX                          0x0
-+#define POST_COE_MIN                          0x10
-+#define ZERO_COE_MAX                          0x30
-+#define ZERO_COE_MIN                          0x0
-+
-+/* KR PMD defines */
-+#define PMD_RESET                                     0x1
-+#define PMD_STATUS_SUP_STAT                   0x4
-+#define PMD_STATUS_FRAME_LOCK         0x2
-+#define TRAIN_EN                                      0x3
-+#define TRAIN_DISABLE                         0x1
-+#define RX_STAT                                               0x1
-+
-+/* PCS Link up */
-+#define XFI_PCS_SR1                   0x20
-+#define KR_RX_LINK_STAT_MASK          0x1000
-+
-+/* KX PCS mode register */
-+#define KX_PCS_IF_MODE                                0x8014
-+
-+/* KX PCS mode register init value */
-+#define KX_IF_MODE_INIT                               0x8
-+
-+/* KX/KR AN registers */
-+#define AN_CTRL_INIT                          0x1200
-+#define KX_AN_AD1_INIT                                0x25
-+#define KR_AN_AD1_INIT_10G                    0x85
-+#define KR_AN_AD1_INIT_40G                    0x105
-+#define AN_LNK_UP_MASK                                0x4
-+#define KR_AN_MASK_10G                                0x8
-+#define KR_AN_MASK_40G                                0x20
-+#define TRAIN_FAIL                                    0x8
-+#define KR_AN_40G_MDIO_OFFSET         4
-+
-+/* XGKR Timeouts */
-+#define XGKR_TIMEOUT                          1050
-+#define XGKR_DENY_RT_INTERVAL         3000
-+#define XGKR_AN_WAIT_ITERATIONS       5
-+
-+/* XGKR Increment/Decrement Requests */
-+#define INCREMENT                                     1
-+#define DECREMENT                                     2
-+#define TIMEOUT_LONG                          3
-+#define TIMEOUT_M1                                    3
-+
-+/* XGKR Masks */
-+#define RX_READY_MASK                         0x8000
-+#define PRESET_MASK                                   0x2000
-+#define INIT_MASK                                     0x1000
-+#define COP1_MASK                                     0x30
-+#define COP1_SHIFT                                    4
-+#define COZ_MASK                                      0xc
-+#define COZ_SHIFT                                     2
-+#define COM1_MASK                                     0x3
-+#define COM1_SHIFT                                    0
-+#define REQUEST_MASK                          0x3f
-+#define LD_ALL_MASK                   (PRESET_MASK | INIT_MASK | \
-+                                      COP1_MASK | COZ_MASK | COM1_MASK)
-+
-+/* Lanes definitions */
-+#define MASTER_LANE                                   0
-+#define SINGLE_LANE                                   0
-+#define MAX_PHY_LANES_NO                      4
-+
-+/* Invalid value */
-+#define VAL_INVALID                           0xff
-+
-+/* New XGKR Training Algorithm */
-+#define NEW_ALGORITHM_TRAIN_TX
-+
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+#define       FORCE_INC_COP1_NUMBER           0
-+#define       FORCE_INC_COM1_NUMBER           1
-+#endif
-+
-+/* Link_Training_Registers offsets */
-+static int lt_MDIO_MMD = 0;
-+static u32 lt_KR_PMD_CTRL = 0;
-+static u32 lt_KR_PMD_STATUS = 0;
-+static u32 lt_KR_LP_CU = 0;
-+static u32 lt_KR_LP_STATUS = 0;
-+static u32 lt_KR_LD_CU = 0;
-+static u32 lt_KR_LD_STATUS = 0;
-+
-+/* KX/KR AN registers offsets */
-+static u32 g_an_AD1 = 0;
-+static u32 g_an_BP_STAT = 0;
-+
-+static const u32 preq_table[] = {0x0, 0x1, 0x3, 0x5,
-+                               0x7, 0x9, 0xb, 0xc, VAL_INVALID};
-+static const u32 pst1q_table[] = {0x0, 0x1, 0x3, 0x5, 0x7,
-+                                0x9, 0xb, 0xd, 0xf, 0x10, VAL_INVALID};
-+
-+enum backplane_mode {
-+      PHY_BACKPLANE_1000BASE_KX,
-+      PHY_BACKPLANE_10GBASE_KR,
-+      PHY_BACKPLANE_40GBASE_KR,
-+      PHY_BACKPLANE_INVAL
-+};
-+
-+enum serdes_type {
-+      SERDES_10G,
-+      SERDES_28G,
-+      SERDES_INVAL
-+};
-+
-+enum coe_filed {
-+      COE_COP1,
-+      COE_COZ,
-+      COE_COM
-+};
-+
-+enum coe_update {
-+      COE_NOTUPDATED,
-+      COE_UPDATED,
-+      COE_MIN,
-+      COE_MAX,
-+      COE_INV
-+};
-+
-+enum train_state {
-+      DETECTING_LP,
-+      TRAINED,
-+};
-+
-+struct tx_condition {
-+      bool bin_m1_late_early;
-+      bool bin_long_late_early;
-+      bool bin_m1_stop;
-+      bool bin_long_stop;
-+      bool tx_complete;
-+      bool sent_init;
-+      int m1_min_max_cnt;
-+      int long_min_max_cnt;
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+      int pre_inc;
-+      int post_inc;
-+#endif
-+};
-+
-+struct xgkr_params {
-+      void *reg_base;         /* lane memory map: registers base address */
-+      int idx;                        /* lane relative index inside a multi-lane PHY */
-+      struct phy_device *phydev;
-+      struct serdes_access *srds;
-+      struct tx_condition tx_c;
-+      struct delayed_work xgkr_wk;
-+      enum train_state state;
-+      int an_wait_count;
-+      unsigned long rt_time;
-+      u32 ld_update;
-+      u32 ld_status;
-+      u32 ratio_preq;
-+      u32 ratio_pst1q;
-+      u32 adpt_eq;
-+      u32 tuned_ratio_preq;
-+      u32 tuned_ratio_pst1q;
-+      u32 tuned_adpt_eq;
-+};
-+
-+struct xgkr_phy_data {
-+      int bp_mode;
-+      u32 phy_lanes;
-+      struct mutex phy_lock;
-+      bool aneg_done;
-+      struct xgkr_params xgkr[MAX_PHY_LANES_NO];
-+};
-+
-+static void setup_an_lt_ls(void)
-+{
-+      /* KR PMD registers */
-+      lt_MDIO_MMD = MDIO_MMD_PMAPMD;
-+      lt_KR_PMD_CTRL = 0x96;
-+      lt_KR_PMD_STATUS = 0x97;
-+      lt_KR_LP_CU = 0x98;
-+      lt_KR_LP_STATUS = 0x99;
-+      lt_KR_LD_CU = 0x9a;
-+      lt_KR_LD_STATUS = 0x9b;
-+
-+      /* KX/KR AN registers */
-+      g_an_AD1 = 0x11;
-+      g_an_BP_STAT = 0x30;
-+}
-+
-+static void setup_an_lt_lx(void)
-+{
-+      /* Auto-Negotiation and Link Training Core Registers page 1: 256 = 0x100 */
-+      lt_MDIO_MMD = MDIO_MMD_AN;
-+      lt_KR_PMD_CTRL = 0x100;
-+      lt_KR_PMD_STATUS = 0x101;
-+      lt_KR_LP_CU = 0x102;
-+      lt_KR_LP_STATUS = 0x103;
-+      lt_KR_LD_CU = 0x104;
-+      lt_KR_LD_STATUS = 0x105;
-+
-+      /* KX/KR AN registers */
-+      g_an_AD1 = 0x03;
-+      g_an_BP_STAT = 0x0F;
-+}
-+
-+static u32 le_ioread32(u32 *reg)
-+{
-+      return ioread32(reg);
-+}
-+
-+static void le_iowrite32(u32 value, u32 *reg)
-+{
-+      iowrite32(value, reg);
-+}
-+
-+static u32 be_ioread32(u32 *reg)
-+{
-+      return ioread32be(reg);
-+}
-+
-+static void be_iowrite32(u32 value, u32 *reg)
-+{
-+      iowrite32be(value, reg);
-+}
-+
-+/**
-+ * xgkr_phy_write_mmd - Wrapper function for phy_write_mmd
-+ * for writing a register on an MMD on a given PHY.
-+ *
-+ * Same rules as for phy_write_mmd();
-+ */
-+static int xgkr_phy_write_mmd(struct xgkr_params *xgkr, int devad, u32 regnum, u16 val)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int mdio_addr = phydev->mdio.addr;
-+      int err;
-+
-+      mutex_lock(&xgkr_inst->phy_lock);
-+
-+      if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR && devad == MDIO_MMD_AN) {
-+              //40G AN: prepare mdio address for writing phydev AN registers for 40G on respective lane
-+              phydev->mdio.addr = KR_AN_40G_MDIO_OFFSET + xgkr->idx;
-+      }
-+
-+      err = phy_write_mmd(phydev, devad, regnum, val);
-+      if (err)
-+              dev_err(&phydev->mdio.dev, "Writing PHY (%p) MMD = 0x%02x register = 0x%02x failed with error code: 0x%08x \n", phydev, devad, regnum, err);
-+
-+      if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR && devad == MDIO_MMD_AN) {
-+              //40G AN: restore mdio address
-+              phydev->mdio.addr = mdio_addr;
-+      }
-+
-+      mutex_unlock(&xgkr_inst->phy_lock);
-+
-+      return err;
-+}
-+
-+/**
-+ * xgkr_phy_read_mmd - Wrapper function for phy_read_mmd
-+ * for reading a register from an MMD on a given PHY.
-+ *
-+ * Same rules as for phy_read_mmd();
-+ */
-+static int xgkr_phy_read_mmd(struct xgkr_params *xgkr, int devad, u32 regnum)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int mdio_addr = phydev->mdio.addr;
-+      int ret;
-+
-+      mutex_lock(&xgkr_inst->phy_lock);
-+
-+      if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR && devad == MDIO_MMD_AN) {
-+              //40G AN: prepare mdio address for reading phydev AN registers for 40G on respective lane
-+              phydev->mdio.addr = KR_AN_40G_MDIO_OFFSET + xgkr->idx;
-+      }
-+
-+      ret = phy_read_mmd(phydev, devad, regnum);
-+
-+      if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR && devad == MDIO_MMD_AN) {
-+              //40G AN: restore mdio address
-+              phydev->mdio.addr = mdio_addr;
-+      }
-+
-+      mutex_unlock(&xgkr_inst->phy_lock);
-+
-+      return ret;
-+}
-+
-+static void tx_condition_init(struct tx_condition *tx_c)
-+{
-+      tx_c->bin_m1_late_early = true;
-+      tx_c->bin_long_late_early = false;
-+      tx_c->bin_m1_stop = false;
-+      tx_c->bin_long_stop = false;
-+      tx_c->tx_complete = false;
-+      tx_c->sent_init = false;
-+      tx_c->m1_min_max_cnt = 0;
-+      tx_c->long_min_max_cnt = 0;
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+      tx_c->pre_inc = FORCE_INC_COM1_NUMBER;
-+      tx_c->post_inc = FORCE_INC_COP1_NUMBER;
-+#endif
-+}
-+
-+void tune_tecr(struct xgkr_params *xgkr)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      bool reset = false;
-+      
-+      if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR) {
-+              /* Reset only the Master Lane */
-+              reset = (xgkr->idx == MASTER_LANE);
-+      } else {
-+              reset = true;
-+      }
-+      
-+      xgkr->srds->tune_tecr(xgkr->reg_base, xgkr->ratio_preq, xgkr->ratio_pst1q, xgkr->adpt_eq, reset);
-+
-+      xgkr->tuned_ratio_preq = xgkr->ratio_preq;
-+      xgkr->tuned_ratio_pst1q = xgkr->ratio_pst1q;
-+      xgkr->tuned_adpt_eq = xgkr->adpt_eq;
-+}
-+
-+static void start_lt(struct xgkr_params *xgkr)
-+{
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_PMD_CTRL, TRAIN_EN);
-+}
-+
-+static void stop_lt(struct xgkr_params *xgkr)
-+{
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_PMD_CTRL, TRAIN_DISABLE);
-+}
-+
-+static void reset_lt(struct xgkr_params *xgkr)
-+{
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, MDIO_CTRL1, PMD_RESET);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_PMD_CTRL, TRAIN_DISABLE);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_LD_CU, 0);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_LD_STATUS, 0);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_PMD_STATUS, 0);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_LP_CU, 0);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD, lt_KR_LP_STATUS, 0);
-+      
-+}
-+
-+static void ld_coe_status(struct xgkr_params *xgkr)
-+{
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD,
-+                    lt_KR_LD_STATUS, xgkr->ld_status);
-+}
-+
-+static void ld_coe_update(struct xgkr_params *xgkr)
-+{
-+      dev_dbg(&xgkr->phydev->mdio.dev, "sending request: %x\n", xgkr->ld_update);
-+      xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD,
-+                    lt_KR_LD_CU, xgkr->ld_update);
-+}
-+
-+static void start_xgkr_state_machine(struct delayed_work *work)
-+{
-+      queue_delayed_work(system_power_efficient_wq, work,
-+                         msecs_to_jiffies(XGKR_TIMEOUT));
-+}
-+
-+static void start_xgkr_an(struct xgkr_params *xgkr)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int i;
-+      int err;
-+
-+      switch (xgkr_inst->bp_mode)
-+      {
-+      case PHY_BACKPLANE_1000BASE_KX:
-+              dev_err(&phydev->mdio.dev, "Wrong call path for 1000Base-KX \n");
-+              break;
-+
-+      case PHY_BACKPLANE_10GBASE_KR:
-+              err = xgkr_phy_write_mmd(xgkr, MDIO_MMD_AN, g_an_AD1, KR_AN_AD1_INIT_10G);
-+              if (err)
-+                      dev_err(&phydev->mdio.dev, "Setting AN register 0x%02x failed with error code: 0x%08x \n", g_an_AD1, err);
-+              udelay(1);
-+              err = xgkr_phy_write_mmd(xgkr, MDIO_MMD_AN, MDIO_CTRL1, AN_CTRL_INIT);
-+              if (err)
-+                      dev_err(&phydev->mdio.dev, "Setting AN register 0x%02x failed with error code: 0x%08x \n", MDIO_CTRL1, err);
-+              break;
-+
-+      case PHY_BACKPLANE_40GBASE_KR:
-+              if (xgkr->idx == MASTER_LANE) {
-+                      for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                              err = xgkr_phy_write_mmd(&xgkr_inst->xgkr[i], MDIO_MMD_AN, g_an_AD1, KR_AN_AD1_INIT_40G);
-+                              if (err)
-+                                      dev_err(&phydev->mdio.dev, "Setting AN register 0x%02x on lane %d failed with error code: 0x%08x \n", g_an_AD1, xgkr_inst->xgkr[i].idx, err);
-+                      }
-+                      udelay(1);
-+                      err = xgkr_phy_write_mmd(xgkr, MDIO_MMD_AN, MDIO_CTRL1, AN_CTRL_INIT);
-+                      if (err)
-+                              dev_err(&phydev->mdio.dev, "Setting AN register 0x%02x on Master Lane failed with error code: 0x%08x \n", MDIO_CTRL1, err);
-+              }
-+              break;
-+      }
-+}
-+
-+static void start_1gkx_an(struct phy_device *phydev)
-+{
-+      phy_write_mmd(phydev, MDIO_MMD_PCS, KX_PCS_IF_MODE, KX_IF_MODE_INIT);
-+      phy_write_mmd(phydev, MDIO_MMD_AN, g_an_AD1, KX_AN_AD1_INIT);
-+      phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
-+      phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, AN_CTRL_INIT);
-+}
-+
-+static void reset_tecr(struct xgkr_params *xgkr)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+
-+      switch (xgkr_inst->bp_mode)
-+      {
-+      case PHY_BACKPLANE_1000BASE_KX:
-+              dev_err(&phydev->mdio.dev, "Wrong call path for 1000Base-KX \n");
-+              break;
-+
-+      case PHY_BACKPLANE_10GBASE_KR:
-+              xgkr->ratio_preq = RATIO_PREQ_10G;
-+              xgkr->ratio_pst1q = RATIO_PST1Q_10G;
-+              xgkr->adpt_eq = RATIO_EQ_10G;
-+              break;
-+
-+      case PHY_BACKPLANE_40GBASE_KR:
-+              xgkr->ratio_preq = RATIO_PREQ_40G;
-+              xgkr->ratio_pst1q = RATIO_PST1Q_40G;
-+              xgkr->adpt_eq = RATIO_EQ_40G;
-+              break;
-+      }
-+
-+      tune_tecr(xgkr);
-+}
-+
-+static void init_xgkr(struct xgkr_params *xgkr, int reset)
-+{
-+      if (reset)
-+              reset_tecr(xgkr);
-+
-+      tx_condition_init(&xgkr->tx_c);
-+      xgkr->state = DETECTING_LP;
-+
-+      xgkr->ld_status &= RX_READY_MASK;
-+      ld_coe_status(xgkr);
-+      xgkr->ld_update = 0;
-+      xgkr->ld_status &= ~RX_READY_MASK;
-+      ld_coe_status(xgkr);
-+
-+}
-+
-+static void initialize(struct xgkr_params *xgkr)
-+{
-+      reset_tecr(xgkr);
-+
-+      xgkr->ld_status &= ~(COP1_MASK | COZ_MASK | COM1_MASK);
-+      xgkr->ld_status |= COE_UPDATED << COP1_SHIFT |
-+                         COE_UPDATED << COZ_SHIFT |
-+                         COE_UPDATED << COM1_SHIFT;
-+      ld_coe_status(xgkr);
-+}
-+
-+static void train_remote_tx(struct xgkr_params *xgkr)
-+{
-+      struct tx_condition *tx_c = &xgkr->tx_c;
-+      bool bin_m1_early, bin_long_early;
-+      u32 lp_status, old_ld_update;
-+      u32 status_cop1, status_coz, status_com1;
-+      u32 req_cop1, req_coz, req_com1, req_preset, req_init;
-+      u32 temp;
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+      u32 median_gaink2;
-+#endif
-+
-+recheck:
-+      if (tx_c->bin_long_stop && tx_c->bin_m1_stop) {
-+              tx_c->tx_complete = true;
-+              xgkr->ld_status |= RX_READY_MASK;
-+              ld_coe_status(xgkr);
-+
-+              /* tell LP we are ready */
-+              xgkr_phy_write_mmd(xgkr, lt_MDIO_MMD,
-+                            lt_KR_PMD_STATUS, RX_STAT);
-+
-+              return;
-+      }
-+
-+      /* We start by checking the current LP status. If we got any responses,
-+       * we can clear up the appropriate update request so that the
-+       * subsequent code may easily issue new update requests if needed.
-+       */
-+      lp_status = xgkr_phy_read_mmd(xgkr, lt_MDIO_MMD, lt_KR_LP_STATUS) &
-+                               REQUEST_MASK;
-+
-+      status_cop1 = (lp_status & COP1_MASK) >> COP1_SHIFT;
-+      status_coz = (lp_status & COZ_MASK) >> COZ_SHIFT;
-+      status_com1 = (lp_status & COM1_MASK) >> COM1_SHIFT;
-+
-+      old_ld_update = xgkr->ld_update;
-+      req_cop1 = (old_ld_update & COP1_MASK) >> COP1_SHIFT;
-+      req_coz = (old_ld_update & COZ_MASK) >> COZ_SHIFT;
-+      req_com1 = (old_ld_update & COM1_MASK) >> COM1_SHIFT;
-+      req_preset = old_ld_update & PRESET_MASK;
-+      req_init = old_ld_update & INIT_MASK;
-+
-+      /* IEEE802.3-2008, 72.6.10.2.3.1
-+       * We may clear PRESET when all coefficients show UPDATED or MAX.
-+       */
-+      if (req_preset) {
-+              if ((status_cop1 == COE_UPDATED || status_cop1 == COE_MAX) &&
-+                  (status_coz == COE_UPDATED || status_coz == COE_MAX) &&
-+                  (status_com1 == COE_UPDATED || status_com1 == COE_MAX)) {
-+                      xgkr->ld_update &= ~PRESET_MASK;
-+              }
-+      }
-+
-+      /* IEEE802.3-2008, 72.6.10.2.3.2
-+       * We may clear INITIALIZE when no coefficients show NOT UPDATED.
-+       */
-+      if (req_init) {
-+              if (status_cop1 != COE_NOTUPDATED &&
-+                  status_coz != COE_NOTUPDATED &&
-+                  status_com1 != COE_NOTUPDATED) {
-+                      xgkr->ld_update &= ~INIT_MASK;
-+              }
-+      }
-+
-+      /* IEEE802.3-2008, 72.6.10.2.3.2
-+       * we send initialize to the other side to ensure default settings
-+       * for the LP. Naturally, we should do this only once.
-+       */
-+      if (!tx_c->sent_init) {
-+              if (!lp_status && !(old_ld_update & (LD_ALL_MASK))) {
-+                      xgkr->ld_update = INIT_MASK;
-+                      tx_c->sent_init = true;
-+              }
-+      }
-+
-+      /* IEEE802.3-2008, 72.6.10.2.3.3
-+       * We set coefficient requests to HOLD when we get the information
-+       * about any updates On clearing our prior response, we also update
-+       * our internal status.
-+       */
-+      if (status_cop1 != COE_NOTUPDATED) {
-+              if (req_cop1) {
-+                      xgkr->ld_update &= ~COP1_MASK;
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+                      if (tx_c->post_inc) {
-+                              if (req_cop1 == INCREMENT &&
-+                                  status_cop1 == COE_MAX) {
-+                                      tx_c->post_inc = 0;
-+                                      tx_c->bin_long_stop = true;
-+                                      tx_c->bin_m1_stop = true;
-+                              } else {
-+                                      tx_c->post_inc -= 1;
-+                              }
-+
-+                              ld_coe_update(xgkr);
-+                              goto recheck;
-+                      }
-+#endif
-+                      if ((req_cop1 == DECREMENT && status_cop1 == COE_MIN) ||
-+                          (req_cop1 == INCREMENT && status_cop1 == COE_MAX)) {
-+                              dev_dbg(&xgkr->phydev->mdio.dev, "COP1 hit limit %s",
-+                                      (status_cop1 == COE_MIN) ?
-+                                      "DEC MIN" : "INC MAX");
-+                              tx_c->long_min_max_cnt++;
-+                              if (tx_c->long_min_max_cnt >= TIMEOUT_LONG) {
-+                                      tx_c->bin_long_stop = true;
-+                                      ld_coe_update(xgkr);
-+                                      goto recheck;
-+                              }
-+                      }
-+              }
-+      }
-+
-+      if (status_coz != COE_NOTUPDATED) {
-+              if (req_coz)
-+                      xgkr->ld_update &= ~COZ_MASK;
-+      }
-+
-+      if (status_com1 != COE_NOTUPDATED) {
-+              if (req_com1) {
-+                      xgkr->ld_update &= ~COM1_MASK;
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+                      if (tx_c->pre_inc) {
-+                              if (req_com1 == INCREMENT &&
-+                                  status_com1 == COE_MAX)
-+                                      tx_c->pre_inc = 0;
-+                              else
-+                                      tx_c->pre_inc -= 1;
-+
-+                              ld_coe_update(xgkr);
-+                              goto recheck;
-+                      }
-+#endif
-+                      /* Stop If we have reached the limit for a parameter. */
-+                      if ((req_com1 == DECREMENT && status_com1 == COE_MIN) ||
-+                          (req_com1 == INCREMENT && status_com1 == COE_MAX)) {
-+                              dev_dbg(&xgkr->phydev->mdio.dev, "COM1 hit limit %s",
-+                                      (status_com1 == COE_MIN) ?
-+                                      "DEC MIN" : "INC MAX");
-+                              tx_c->m1_min_max_cnt++;
-+                              if (tx_c->m1_min_max_cnt >= TIMEOUT_M1) {
-+                                      tx_c->bin_m1_stop = true;
-+                                      ld_coe_update(xgkr);
-+                                      goto recheck;
-+                              }
-+                      }
-+              }
-+      }
-+
-+      if (old_ld_update != xgkr->ld_update) {
-+              ld_coe_update(xgkr);
-+              /* Redo these status checks and updates until we have no more
-+               * changes, to speed up the overall process.
-+               */
-+              goto recheck;
-+      }
-+
-+      /* Do nothing if we have pending request. */
-+      if ((req_coz || req_com1 || req_cop1))
-+              return;
-+      else if (lp_status)
-+              /* No pending request but LP status was not reverted to
-+               * not updated.
-+               */
-+              return;
-+
-+#ifdef        NEW_ALGORITHM_TRAIN_TX
-+      if (!(xgkr->ld_update & (PRESET_MASK | INIT_MASK))) {
-+              if (tx_c->pre_inc) {
-+                      xgkr->ld_update = INCREMENT << COM1_SHIFT;
-+                      ld_coe_update(xgkr);
-+                      return;
-+              }
-+
-+              if (status_cop1 != COE_MAX) {
-+                      median_gaink2 = xgkr->srds->get_median_gaink2(xgkr->reg_base);
-+                      if (median_gaink2 == 0xf) {
-+                              tx_c->post_inc = 1;
-+                      } else {
-+                              /* Gaink2 median lower than "F" */
-+                              tx_c->bin_m1_stop = true;
-+                              tx_c->bin_long_stop = true;
-+                              goto recheck;
-+                      }
-+              } else {
-+                      /* C1 MAX */
-+                      tx_c->bin_m1_stop = true;
-+                      tx_c->bin_long_stop = true;
-+                      goto recheck;
-+              }
-+
-+              if (tx_c->post_inc) {
-+                      xgkr->ld_update = INCREMENT << COP1_SHIFT;
-+                      ld_coe_update(xgkr);
-+                      return;
-+              }
-+      }
-+#endif
-+
-+      /* snapshot and select bin */
-+      bin_m1_early = xgkr->srds->is_bin_early(BIN_M1, xgkr->reg_base);
-+      bin_long_early = xgkr->srds->is_bin_early(BIN_LONG, xgkr->reg_base);
-+
-+      if (!tx_c->bin_m1_stop && !tx_c->bin_m1_late_early && bin_m1_early) {
-+              tx_c->bin_m1_stop = true;
-+              goto recheck;
-+      }
-+
-+      if (!tx_c->bin_long_stop &&
-+          tx_c->bin_long_late_early && !bin_long_early) {
-+              tx_c->bin_long_stop = true;
-+              goto recheck;
-+      }
-+
-+      /* IEEE802.3-2008, 72.6.10.2.3.3
-+       * We only request coefficient updates when no PRESET/INITIALIZE is
-+       * pending. We also only request coefficient updates when the
-+       * corresponding status is NOT UPDATED and nothing is pending.
-+       */
-+      if (!(xgkr->ld_update & (PRESET_MASK | INIT_MASK))) {
-+              if (!tx_c->bin_long_stop) {
-+                      /* BinM1 correction means changing COM1 */
-+                      if (!status_com1 && !(xgkr->ld_update & COM1_MASK)) {
-+                              /* Avoid BinM1Late by requesting an
-+                               * immediate decrement.
-+                               */
-+                              if (!bin_m1_early) {
-+                                      /* request decrement c(-1) */
-+                                      temp = DECREMENT << COM1_SHIFT;
-+                                      xgkr->ld_update = temp;
-+                                      ld_coe_update(xgkr);
-+                                      tx_c->bin_m1_late_early = bin_m1_early;
-+                                      return;
-+                              }
-+                      }
-+
-+                      /* BinLong correction means changing COP1 */
-+                      if (!status_cop1 && !(xgkr->ld_update & COP1_MASK)) {
-+                              /* Locate BinLong transition point (if any)
-+                               * while avoiding BinM1Late.
-+                               */
-+                              if (bin_long_early) {
-+                                      /* request increment c(1) */
-+                                      temp = INCREMENT << COP1_SHIFT;
-+                                      xgkr->ld_update = temp;
-+                              } else {
-+                                      /* request decrement c(1) */
-+                                      temp = DECREMENT << COP1_SHIFT;
-+                                      xgkr->ld_update = temp;
-+                              }
-+
-+                              ld_coe_update(xgkr);
-+                              tx_c->bin_long_late_early = bin_long_early;
-+                      }
-+                      /* We try to finish BinLong before we do BinM1 */
-+                      return;
-+              }
-+
-+              if (!tx_c->bin_m1_stop) {
-+                      /* BinM1 correction means changing COM1 */
-+                      if (!status_com1 && !(xgkr->ld_update & COM1_MASK)) {
-+                              /* Locate BinM1 transition point (if any) */
-+                              if (bin_m1_early) {
-+                                      /* request increment c(-1) */
-+                                      temp = INCREMENT << COM1_SHIFT;
-+                                      xgkr->ld_update = temp;
-+                              } else {
-+                                      /* request decrement c(-1) */
-+                                      temp = DECREMENT << COM1_SHIFT;
-+                                      xgkr->ld_update = temp;
-+                              }
-+
-+                              ld_coe_update(xgkr);
-+                              tx_c->bin_m1_late_early = bin_m1_early;
-+                      }
-+              }
-+      }
-+}
-+
-+static int is_link_up(struct phy_device *phydev)
-+{
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int val = 0;
-+      
-+      mutex_lock(&xgkr_inst->phy_lock);
-+
-+      val = phy_read_mmd(phydev, MDIO_MMD_PCS, XFI_PCS_SR1);
-+
-+      mutex_unlock(&xgkr_inst->phy_lock);
-+
-+      return (val & KR_RX_LINK_STAT_MASK) ? 1 : 0;
-+}
-+
-+static int is_link_training_fail(struct xgkr_params *xgkr)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      int val;
-+      int timeout = 100;
-+
-+      val = xgkr_phy_read_mmd(xgkr, lt_MDIO_MMD, lt_KR_PMD_STATUS);
-+
-+      if (!(val & TRAIN_FAIL) && (val & RX_STAT)) {
-+              /* check LNK_STAT for sure */
-+              while (timeout--) {
-+                      if (is_link_up(phydev))
-+                              return 0;
-+
-+                      usleep_range(100, 500);
-+              }
-+      }
-+
-+      return 1;
-+}
-+
-+static int check_rx(struct xgkr_params *xgkr)
-+{
-+      return xgkr_phy_read_mmd(xgkr, lt_MDIO_MMD, lt_KR_LP_STATUS) &
-+                          RX_READY_MASK;
-+}
-+
-+/* Coefficient values have hardware restrictions */
-+static int is_ld_valid(struct xgkr_params *xgkr)
-+{
-+      u32 ratio_pst1q = xgkr->ratio_pst1q;
-+      u32 adpt_eq = xgkr->adpt_eq;
-+      u32 ratio_preq = xgkr->ratio_preq;
-+
-+      if ((ratio_pst1q + adpt_eq + ratio_preq) > 48)
-+              return 0;
-+
-+      if (((ratio_pst1q + adpt_eq + ratio_preq) * 4) >=
-+          ((adpt_eq - ratio_pst1q - ratio_preq) * 17))
-+              return 0;
-+
-+      if (ratio_preq > ratio_pst1q)
-+              return 0;
-+
-+      if (ratio_preq > 8)
-+              return 0;
-+
-+      if (adpt_eq < 26)
-+              return 0;
-+
-+      if (ratio_pst1q > 16)
-+              return 0;
-+
-+      return 1;
-+}
-+
-+static int is_value_allowed(const u32 *val_table, u32 val)
-+{
-+      int i;
-+
-+      for (i = 0;; i++) {
-+              if (*(val_table + i) == VAL_INVALID)
-+                      return 0;
-+              if (*(val_table + i) == val)
-+                      return 1;
-+      }
-+}
-+
-+static enum coe_update inc_dec(struct xgkr_params *xgkr, int field, int request)
-+{
-+      u32 ld_limit[3], ld_coe[3], step[3];
-+
-+      ld_coe[0] = xgkr->ratio_pst1q;
-+      ld_coe[1] = xgkr->adpt_eq;
-+      ld_coe[2] = xgkr->ratio_preq;
-+
-+      /* Information specific to the SerDes for 10GBase-KR:
-+       * Incrementing C(+1) means *decrementing* RATIO_PST1Q
-+       * Incrementing C(0) means incrementing ADPT_EQ
-+       * Incrementing C(-1) means *decrementing* RATIO_PREQ
-+       */
-+      step[0] = -1;
-+      step[1] = 1;
-+      step[2] = -1;
-+
-+      switch (request) {
-+      case INCREMENT:
-+              ld_limit[0] = POST_COE_MAX;
-+              ld_limit[1] = ZERO_COE_MAX;
-+              ld_limit[2] = PRE_COE_MAX;
-+              if (ld_coe[field] != ld_limit[field])
-+                      ld_coe[field] += step[field];
-+              else
-+                      /* MAX */
-+                      return COE_MAX;
-+              break;
-+      case DECREMENT:
-+              ld_limit[0] = POST_COE_MIN;
-+              ld_limit[1] = ZERO_COE_MIN;
-+              ld_limit[2] = PRE_COE_MIN;
-+              if (ld_coe[field] != ld_limit[field])
-+                      ld_coe[field] -= step[field];
-+              else
-+                      /* MIN */
-+                      return COE_MIN;
-+              break;
-+      default:
-+              break;
-+      }
-+
-+      if (is_ld_valid(xgkr)) {
-+              /* accept new ld */
-+              xgkr->ratio_pst1q = ld_coe[0];
-+              xgkr->adpt_eq = ld_coe[1];
-+              xgkr->ratio_preq = ld_coe[2];
-+              /* only some values for preq and pst1q can be used.
-+               * for preq: 0x0, 0x1, 0x3, 0x5, 0x7, 0x9, 0xb, 0xc.
-+               * for pst1q: 0x0, 0x1, 0x3, 0x5, 0x7, 0x9, 0xb, 0xd, 0xf, 0x10.
-+               */
-+              if (!is_value_allowed((const u32 *)&preq_table, ld_coe[2])) {
-+                      dev_dbg(&xgkr->phydev->mdio.dev,
-+                              "preq skipped value: %d\n", ld_coe[2]);
-+                      /* NOT UPDATED */
-+                      return COE_NOTUPDATED;
-+              }
-+
-+              if (!is_value_allowed((const u32 *)&pst1q_table, ld_coe[0])) {
-+                      dev_dbg(&xgkr->phydev->mdio.dev,
-+                              "pst1q skipped value: %d\n", ld_coe[0]);
-+                      /* NOT UPDATED */
-+                      return COE_NOTUPDATED;
-+              }
-+
-+              tune_tecr(xgkr);
-+      } else {
-+              if (request == DECREMENT)
-+                      /* MIN */
-+                      return COE_MIN;
-+              if (request == INCREMENT)
-+                      /* MAX */
-+                      return COE_MAX;
-+      }
-+
-+      /* UPDATED */
-+      return COE_UPDATED;
-+}
-+
-+static void min_max_updated(struct xgkr_params *xgkr, int field, enum coe_update cs)
-+{
-+      u32 mask, val;
-+      u32 ld_cs = cs;
-+
-+      if (cs == COE_INV)
-+              return;
-+
-+      switch (field) {
-+      case COE_COP1:
-+              mask = COP1_MASK;
-+              val = ld_cs << COP1_SHIFT;
-+              break;
-+      case COE_COZ:
-+              mask = COZ_MASK;
-+              val = ld_cs << COZ_SHIFT;
-+              break;
-+      case COE_COM:
-+              mask = COM1_MASK;
-+              val = ld_cs << COM1_SHIFT;
-+              break;
-+      default:
-+              return;
-+      }
-+
-+      xgkr->ld_status &= ~mask;
-+      xgkr->ld_status |= val;
-+}
-+
-+static void check_request(struct xgkr_params *xgkr, int request)
-+{
-+      int cop1_req, coz_req, com_req;
-+      int old_status;
-+      enum coe_update cu;
-+
-+      cop1_req = (request & COP1_MASK) >> COP1_SHIFT;
-+      coz_req = (request & COZ_MASK) >> COZ_SHIFT;
-+      com_req = (request & COM1_MASK) >> COM1_SHIFT;
-+
-+      /* IEEE802.3-2008, 72.6.10.2.5
-+       * Ensure we only act on INCREMENT/DECREMENT when we are in NOT UPDATED
-+       */
-+      old_status = xgkr->ld_status;
-+
-+      if (cop1_req && !(xgkr->ld_status & COP1_MASK)) {
-+              cu = inc_dec(xgkr, COE_COP1, cop1_req);
-+              min_max_updated(xgkr, COE_COP1, cu);
-+      }
-+
-+      if (coz_req && !(xgkr->ld_status & COZ_MASK)) {
-+              cu = inc_dec(xgkr, COE_COZ, coz_req);
-+              min_max_updated(xgkr, COE_COZ, cu);
-+      }
-+
-+      if (com_req && !(xgkr->ld_status & COM1_MASK)) {
-+              cu = inc_dec(xgkr, COE_COM, com_req);
-+              min_max_updated(xgkr, COE_COM, cu);
-+      }
-+
-+      if (old_status != xgkr->ld_status)
-+              ld_coe_status(xgkr);
-+}
-+
-+static void preset(struct xgkr_params *xgkr)
-+{
-+      /* These are all MAX values from the IEEE802.3 perspective. */
-+      xgkr->ratio_pst1q = POST_COE_MAX;
-+      xgkr->adpt_eq = ZERO_COE_MAX;
-+      xgkr->ratio_preq = PRE_COE_MAX;
-+
-+      tune_tecr(xgkr);
-+      xgkr->ld_status &= ~(COP1_MASK | COZ_MASK | COM1_MASK);
-+      xgkr->ld_status |= COE_MAX << COP1_SHIFT |
-+                         COE_MAX << COZ_SHIFT |
-+                         COE_MAX << COM1_SHIFT;
-+      ld_coe_status(xgkr);
-+}
-+
-+static void train_local_tx(struct xgkr_params *xgkr)
-+{
-+      int request, old_ld_status;
-+
-+      /* get request from LP */
-+      request = xgkr_phy_read_mmd(xgkr, lt_MDIO_MMD, lt_KR_LP_CU) &
-+                            (LD_ALL_MASK);
-+
-+      old_ld_status = xgkr->ld_status;
-+
-+      /* IEEE802.3-2008, 72.6.10.2.5
-+       * Ensure we always go to NOT UDPATED for status reporting in
-+       * response to HOLD requests.
-+       * IEEE802.3-2008, 72.6.10.2.3.1/2
-+       * ... but only if PRESET/INITIALIZE are not active to ensure
-+       * we keep status until they are released.
-+       */
-+      if (!(request & (PRESET_MASK | INIT_MASK))) {
-+              if (!(request & COP1_MASK))
-+                      xgkr->ld_status &= ~COP1_MASK;
-+
-+              if (!(request & COZ_MASK))
-+                      xgkr->ld_status &= ~COZ_MASK;
-+
-+              if (!(request & COM1_MASK))
-+                      xgkr->ld_status &= ~COM1_MASK;
-+
-+              if (old_ld_status != xgkr->ld_status)
-+                      ld_coe_status(xgkr);
-+      }
-+
-+      /* As soon as the LP shows ready, no need to do any more updates. */
-+      if (check_rx(xgkr)) {
-+              /* LP receiver is ready */
-+              if (xgkr->ld_status & (COP1_MASK | COZ_MASK | COM1_MASK)) {
-+                      xgkr->ld_status &= ~(COP1_MASK | COZ_MASK | COM1_MASK);
-+                      ld_coe_status(xgkr);
-+              }
-+      } else {
-+              /* IEEE802.3-2008, 72.6.10.2.3.1/2
-+               * only act on PRESET/INITIALIZE if all status is NOT UPDATED.
-+               */
-+              if (request & (PRESET_MASK | INIT_MASK)) {
-+                      if (!(xgkr->ld_status &
-+                            (COP1_MASK | COZ_MASK | COM1_MASK))) {
-+                              if (request & PRESET_MASK)
-+                                      preset(xgkr);
-+
-+                              if (request & INIT_MASK)
-+                                      initialize(xgkr);
-+                      }
-+              }
-+
-+              /* LP Coefficient are not in HOLD */
-+              if (request & REQUEST_MASK)
-+                      check_request(xgkr, request & REQUEST_MASK);
-+      }
-+}
-+
-+static void xgkr_start_train(struct xgkr_params *xgkr)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      struct tx_condition *tx_c = &xgkr->tx_c;
-+      int val = 0, i, j;
-+      int lt_state;
-+      unsigned long dead_line;
-+      int lp_rx_ready, tx_training_complete;
-+      u32 lt_timeout = 500;
-+
-+      init_xgkr(xgkr, 0);
-+      
-+      start_lt(xgkr);
-+      
-+      if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR) {
-+              lt_timeout = 2000;
-+      }
-+
-+      for (i = 0; i < 2;) {
-+              
-+              dead_line = jiffies + msecs_to_jiffies(lt_timeout);
-+              
-+              while (time_before(jiffies, dead_line)) {
-+
-+                      val = xgkr_phy_read_mmd(xgkr, lt_MDIO_MMD,
-+                                         lt_KR_PMD_STATUS);
-+
-+                      if (val & TRAIN_FAIL) {
-+                              /* LT failed already, reset lane to avoid
-+                               * it run into hanging, then start LT again.
-+                               */
-+                              if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR) {
-+                                      /* Reset only the Master Lane */
-+                                      if (xgkr->idx == MASTER_LANE)
-+                                              xgkr->srds->reset_lane(xgkr->reg_base);
-+                              } else {
-+                                      xgkr->srds->reset_lane(xgkr->reg_base);
-+                              }
-+                              
-+                              start_lt(xgkr);
-+                      } else if ((val & PMD_STATUS_SUP_STAT) &&
-+                                 (val & PMD_STATUS_FRAME_LOCK))
-+                              break;
-+                      usleep_range(100, 500);
-+              }
-+
-+              if (!((val & PMD_STATUS_FRAME_LOCK) &&
-+                    (val & PMD_STATUS_SUP_STAT))) {
-+                      i++;
-+                      continue;
-+              }
-+
-+              /* init process */
-+              lp_rx_ready = false;
-+              tx_training_complete = false;
-+              /* the LT should be finished in 500ms, failed or OK. */
-+              dead_line = jiffies + msecs_to_jiffies(lt_timeout);
-+
-+              while (time_before(jiffies, dead_line)) {
-+                      /* check if the LT is already failed */
-+
-+                      lt_state = xgkr_phy_read_mmd(xgkr, lt_MDIO_MMD,
-+                                              lt_KR_PMD_STATUS);
-+
-+                      if (lt_state & TRAIN_FAIL) {
-+                              
-+                              if (xgkr_inst->bp_mode == PHY_BACKPLANE_40GBASE_KR) {
-+                                      /* Reset only the Master Lane */
-+                                      if (xgkr->idx == MASTER_LANE)
-+                                              xgkr->srds->reset_lane(xgkr->reg_base);
-+                              } else {
-+                                      xgkr->srds->reset_lane(xgkr->reg_base);
-+                              }
-+                              
-+                              break;
-+                      }
-+
-+                      lp_rx_ready = check_rx(xgkr);
-+                      tx_training_complete = tx_c->tx_complete;
-+
-+                      if (lp_rx_ready && tx_training_complete)
-+                              break;
-+
-+                      if (!lp_rx_ready)
-+                              train_local_tx(xgkr);
-+
-+                      if (!tx_training_complete)
-+                              train_remote_tx(xgkr);
-+
-+                      usleep_range(100, 500);
-+              }
-+
-+              i++;
-+              /* check LT result */
-+              if (is_link_training_fail(xgkr)) {
-+                      init_xgkr(xgkr, 0);
-+                      continue;
-+              } else {
-+                      stop_lt(xgkr);
-+                      xgkr->state = TRAINED;
-+                      
-+                      switch (xgkr_inst->bp_mode)
-+                      {
-+                      case PHY_BACKPLANE_10GBASE_KR:
-+                              if (phydev->attached_dev == NULL)
-+                                      dev_info(&phydev->mdio.dev, "10GBase-KR link trained (Tx equalization: RATIO_PREQ = 0x%x, RATIO_PST1Q = 0x%x, ADPT_EQ = 0x%x)\n",
-+                                                      xgkr->tuned_ratio_preq, xgkr->tuned_ratio_pst1q, xgkr->tuned_adpt_eq);
-+                              else
-+                                      dev_info(&phydev->mdio.dev, "%s %s: 10GBase-KR link trained (Tx equalization: RATIO_PREQ = 0x%x, RATIO_PST1Q = 0x%x, ADPT_EQ = 0x%x)\n",
-+                                                      dev_driver_string(phydev->attached_dev->dev.parent), 
-+                                                      dev_name(phydev->attached_dev->dev.parent),
-+                                                      xgkr->tuned_ratio_preq, xgkr->tuned_ratio_pst1q, xgkr->tuned_adpt_eq);
-+                              break;
-+                              
-+                      case PHY_BACKPLANE_40GBASE_KR:
-+                              if (xgkr->idx == xgkr_inst->phy_lanes - 1) {
-+                                      if (phydev->attached_dev == NULL)
-+                                              dev_info(&phydev->mdio.dev, "40GBase-KR link trained at lanes Tx equalization:\n");
-+                                      else
-+                                              dev_info(&phydev->mdio.dev, "%s %s: 40GBase-KR link trained at lanes Tx equalization:\n",
-+                                                              dev_driver_string(phydev->attached_dev->dev.parent), 
-+                                                              dev_name(phydev->attached_dev->dev.parent));
-+
-+                                      for (j = 0; j < xgkr_inst->phy_lanes; j++) {
-+                                              if (phydev->attached_dev == NULL)
-+                                                      dev_info(&phydev->mdio.dev, "40GBase-KR Lane %d: RATIO_PREQ = 0x%x, RATIO_PST1Q = 0x%x, ADPT_EQ = 0x%x\n",
-+                                                                      j, xgkr_inst->xgkr[j].tuned_ratio_preq, xgkr_inst->xgkr[j].tuned_ratio_pst1q, xgkr_inst->xgkr[j].tuned_adpt_eq);
-+                                              else
-+                                                      dev_info(&phydev->mdio.dev, "%s %s: 40GBase-KR Lane %d: RATIO_PREQ = 0x%x, RATIO_PST1Q = 0x%x, ADPT_EQ = 0x%x\n",
-+                                                                      dev_driver_string(phydev->attached_dev->dev.parent),
-+                                                                      dev_name(phydev->attached_dev->dev.parent),
-+                                                                      j, xgkr_inst->xgkr[j].tuned_ratio_preq, xgkr_inst->xgkr[j].tuned_ratio_pst1q, xgkr_inst->xgkr[j].tuned_adpt_eq);
-+                                      }
-+                              }
-+                              break;
-+                      }
-+
-+                      break;
-+              }
-+      }
-+}
-+
-+static void xgkr_request_restart_an(struct xgkr_params *xgkr)
-+{
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int i;
-+
-+      if (time_before(jiffies, xgkr->rt_time))
-+              return;
-+      
-+      switch (xgkr_inst->bp_mode)
-+      {
-+      case PHY_BACKPLANE_1000BASE_KX:
-+              dev_err(&phydev->mdio.dev, "Wrong call path for 1000Base-KX \n");
-+              break;
-+
-+      case PHY_BACKPLANE_10GBASE_KR:
-+              init_xgkr(xgkr, 0);  
-+              reset_lt(xgkr);
-+              xgkr->state = DETECTING_LP;
-+              start_xgkr_an(xgkr);
-+              start_xgkr_state_machine(&xgkr->xgkr_wk);
-+              break;
-+
-+      case PHY_BACKPLANE_40GBASE_KR:
-+              for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                      init_xgkr(&xgkr_inst->xgkr[i], 0);
-+                      reset_lt(&xgkr_inst->xgkr[i]);
-+                      xgkr_inst->xgkr[i].state = DETECTING_LP;
-+              }
-+              //Start AN only for Master Lane
-+              start_xgkr_an(&xgkr_inst->xgkr[MASTER_LANE]);
-+              //start state machine
-+              for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                      start_xgkr_state_machine(&xgkr_inst->xgkr[i].xgkr_wk);
-+              }
-+              break;
-+      }
-+      
-+      xgkr->rt_time = jiffies + msecs_to_jiffies(XGKR_DENY_RT_INTERVAL);
-+}
-+
-+static void xgkr_state_machine(struct work_struct *work)
-+{
-+      struct delayed_work *dwork = to_delayed_work(work);
-+      struct xgkr_params *xgkr = container_of(dwork,
-+                                                struct xgkr_params, xgkr_wk);
-+      struct phy_device *phydev = xgkr->phydev;
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int an_state;
-+      bool start_train = false;
-+      bool all_lanes_trained = false;
-+      int i;
-+
-+      if (!xgkr_inst->aneg_done) {
-+              start_xgkr_state_machine(&xgkr->xgkr_wk);
-+              return;
-+      }
-+
-+      mutex_lock(&phydev->lock);
-+      
-+      switch (xgkr->state) {
-+      case DETECTING_LP:
-+
-+              switch (xgkr_inst->bp_mode)
-+              {
-+              case PHY_BACKPLANE_1000BASE_KX:
-+                      dev_err(&phydev->mdio.dev, "Wrong call path for 1000Base-KX \n");
-+                      break;
-+
-+              case PHY_BACKPLANE_10GBASE_KR:
-+                      an_state = xgkr_phy_read_mmd(xgkr, MDIO_MMD_AN, g_an_BP_STAT);
-+                      if (an_state & KR_AN_MASK_10G) {
-+                              //AN acquired: Train the lane
-+                              xgkr->an_wait_count = 0;
-+                              start_train = true;
-+                      } else {
-+                              //AN lost or not yet acquired
-+                              if (!is_link_up(phydev)) {
-+                                      //Link is down: restart training
-+                                      xgkr->an_wait_count = 0;
-+                                      xgkr_request_restart_an(xgkr);
-+                              } else {
-+                                      //Link is up: wait few iterations for AN to be acquired
-+                                      if (xgkr->an_wait_count >= XGKR_AN_WAIT_ITERATIONS) {
-+                                              xgkr->an_wait_count = 0;
-+                                              xgkr_request_restart_an(xgkr);
-+                                      } else {
-+                                              xgkr->an_wait_count++;
-+                                      }
-+                              }
-+                      }
-+                      break;
-+
-+              case PHY_BACKPLANE_40GBASE_KR:
-+                      //Check AN state only on Master Lane
-+                      an_state = xgkr_phy_read_mmd(&xgkr_inst->xgkr[MASTER_LANE], MDIO_MMD_AN, g_an_BP_STAT);
-+                      if (an_state & KR_AN_MASK_40G) {
-+                              //AN acquired: Train all lanes in order starting with Master Lane
-+                              xgkr->an_wait_count = 0;
-+                              if (xgkr->idx == MASTER_LANE) {
-+                                      start_train = true;
-+                              }
-+                              else if (xgkr_inst->xgkr[xgkr->idx - 1].state == TRAINED) {
-+                                      start_train = true;
-+                              }
-+                      } else {
-+                              //AN lost or not yet acquired
-+                              if (!is_link_up(phydev)) {
-+                                      //Link is down: restart training
-+                                      xgkr->an_wait_count = 0;
-+                                      xgkr_request_restart_an(xgkr);
-+                              } else {
-+                                      //Link is up: wait few iterations for AN to be acquired
-+                                      if (xgkr->an_wait_count >= XGKR_AN_WAIT_ITERATIONS) {
-+                                              xgkr->an_wait_count = 0;
-+                                              xgkr_request_restart_an(xgkr);
-+                                      } else {
-+                                              xgkr->an_wait_count++;
-+                                      }
-+                              }
-+                      }
-+                      break;
-+              }
-+              break;
-+
-+      case TRAINED:
-+              if (!is_link_up(phydev)) {
-+                      switch (xgkr_inst->bp_mode)
-+                      {
-+                      case PHY_BACKPLANE_1000BASE_KX:
-+                              dev_err(&phydev->mdio.dev, "Wrong call path for 1000Base-KX \n");
-+                              break;
-+
-+                      case PHY_BACKPLANE_10GBASE_KR:
-+                              dev_info(&phydev->mdio.dev, "Detect hotplug, restart training\n");
-+                              xgkr_request_restart_an(xgkr);
-+                              break;
-+
-+                      case PHY_BACKPLANE_40GBASE_KR:
-+                              if (xgkr->idx == MASTER_LANE) {
-+                                      //check if all lanes are trained only on Master Lane
-+                                      all_lanes_trained = true;
-+                                      for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                                              if (xgkr_inst->xgkr[i].state != TRAINED) {
-+                                                      all_lanes_trained = false;
-+                                                      break;
-+                                              }
-+                                      }
-+                                      if (all_lanes_trained) {
-+                                              dev_info(&phydev->mdio.dev, "Detect hotplug, restart training\n");
-+                                              xgkr_request_restart_an(xgkr);
-+                                      }
-+                              }
-+                              break;
-+                      }
-+              }
-+              break;
-+      }
-+
-+      if (start_train) {
-+              xgkr_start_train(xgkr);
-+      }
-+
-+      mutex_unlock(&phydev->lock);
-+      start_xgkr_state_machine(&xgkr->xgkr_wk);
-+}
-+
-+static int fsl_backplane_probe(struct phy_device *phydev)
-+{
-+      struct xgkr_phy_data *xgkr_inst;
-+      struct device_node *phy_node, *lane_node;
-+      struct resource res_lane;
-+      struct serdes_access *srds = NULL;
-+      int serdes_type;
-+      const char *st;
-+      const char *bm;
-+      int ret, i, phy_lanes;
-+      int bp_mode;
-+      u32 lane_base_addr[MAX_PHY_LANES_NO], lane_memmap_size;
-+
-+      phy_node = phydev->mdio.dev.of_node;
-+      if (!phy_node) {
-+              dev_err(&phydev->mdio.dev, "No associated device tree node\n");
-+              return -EINVAL;
-+      }
-+
-+      bp_mode = of_property_read_string(phy_node, "backplane-mode", &bm);
-+      if (bp_mode < 0)
-+              return -EINVAL;
-+
-+      phy_lanes = 1;
-+      if (!strcasecmp(bm, "1000base-kx")) {
-+              bp_mode = PHY_BACKPLANE_1000BASE_KX;
-+      } else if (!strcasecmp(bm, "10gbase-kr")) {
-+              bp_mode = PHY_BACKPLANE_10GBASE_KR;
-+      } else if (!strcasecmp(bm, "40gbase-kr")) {
-+              bp_mode = PHY_BACKPLANE_40GBASE_KR;
-+              phy_lanes = 4;
-+      } else {
-+              dev_err(&phydev->mdio.dev, "Unknown backplane-mode\n");
-+              return -EINVAL;
-+      }
-+
-+      lane_node = of_parse_phandle(phy_node, "fsl,lane-handle", 0);
-+      if (!lane_node) {
-+              dev_err(&phydev->mdio.dev, "parse fsl,lane-handle failed\n");
-+              return -EINVAL;
-+      }
-+
-+      ret = of_property_read_string(lane_node, "compatible", &st);
-+      if (ret < 0) {
-+              //assume SERDES-10G if compatible property is not specified
-+              serdes_type = SERDES_10G;
-+      }
-+      else if (!strcasecmp(st, "fsl,serdes-10g")) {
-+              serdes_type = SERDES_10G;
-+      } else if (!strcasecmp(st, "fsl,serdes-28g")) {
-+              serdes_type = SERDES_28G;
-+      } else {
-+              dev_err(&phydev->mdio.dev, "Unknown serdes-type\n");
-+              return -EINVAL;
-+      }
-+
-+      ret = of_address_to_resource(lane_node, 0, &res_lane);
-+      if (ret) {
-+              dev_err(&phydev->mdio.dev, "could not obtain memory map\n");
-+              return ret;
-+      }
-+
-+      of_node_put(lane_node);
-+      ret = of_property_read_u32_array(phy_node, "fsl,lane-reg",
-+                                       (u32 *)lane_base_addr, phy_lanes);
-+      if (ret) {
-+              dev_err(&phydev->mdio.dev, "could not get fsl,lane-reg\n");
-+              return -EINVAL;
-+      }
-+
-+      switch (serdes_type)
-+      {
-+      case SERDES_10G:
-+              setup_an_lt_ls();
-+              srds = setup_serdes_access_10g();
-+              break;
-+
-+      case SERDES_28G:
-+              setup_an_lt_lx();
-+              srds = setup_serdes_access_28g();
-+              break;
-+
-+      default:
-+              dev_err(&phydev->mdio.dev, "Unsupported serdes-type\n");
-+              return -EINVAL;
-+      }
-+
-+      if (!srds) {
-+              dev_err(&phydev->mdio.dev, "Unsupported serdes-type\n");
-+              return -EINVAL;
-+      }
-+
-+      srds->serdes_type = serdes_type;
-+      srds->is_little_endian = of_property_read_bool(lane_node, "little-endian");
-+
-+      if (srds->is_little_endian) {
-+              srds->ioread32 = le_ioread32;
-+              srds->iowrite32 = le_iowrite32;
-+      } else {
-+              srds->ioread32 = be_ioread32;
-+              srds->iowrite32 = be_iowrite32;
-+      }
-+
-+      xgkr_inst = devm_kzalloc(&phydev->mdio.dev,
-+                               sizeof(*xgkr_inst), GFP_KERNEL);
-+      if (!xgkr_inst)
-+              return -ENOMEM;
-+
-+      xgkr_inst->phy_lanes = phy_lanes;
-+      xgkr_inst->bp_mode = bp_mode;
-+      mutex_init(&xgkr_inst->phy_lock);
-+
-+      lane_memmap_size = srds->get_lane_memmap_size();
-+      
-+      for (i = 0; i < phy_lanes; i++) {
-+              xgkr_inst->xgkr[i].idx = i;
-+              xgkr_inst->xgkr[i].phydev = phydev;
-+              xgkr_inst->xgkr[i].srds = srds;
-+              xgkr_inst->xgkr[i].reg_base = devm_ioremap_nocache(&phydev->mdio.dev,
-+                                                  res_lane.start + lane_base_addr[i],
-+                                                  lane_memmap_size);
-+              if (!xgkr_inst->xgkr[i].reg_base) {
-+                      dev_err(&phydev->mdio.dev, "ioremap_nocache failed\n");
-+                      return -ENOMEM;
-+              }
-+              xgkr_inst->xgkr[i].rt_time = jiffies + msecs_to_jiffies(XGKR_DENY_RT_INTERVAL);
-+      }
-+
-+      phydev->priv = xgkr_inst;
-+
-+      switch (bp_mode)
-+      {
-+      case PHY_BACKPLANE_1000BASE_KX:
-+              phydev->speed = SPEED_1000;
-+              /* configure the lane for 1000BASE-KX */
-+              srds->lane_set_1gkx(xgkr_inst->xgkr[SINGLE_LANE].reg_base);
-+              break;
-+
-+      case PHY_BACKPLANE_10GBASE_KR:
-+              phydev->speed = SPEED_10000;
-+              INIT_DELAYED_WORK(&xgkr_inst->xgkr[SINGLE_LANE].xgkr_wk, xgkr_state_machine);
-+              break;
-+
-+      case PHY_BACKPLANE_40GBASE_KR:
-+              phydev->speed = SPEED_40000;
-+              for (i = 0; i < phy_lanes; i++)
-+                      INIT_DELAYED_WORK(&xgkr_inst->xgkr[i].xgkr_wk, xgkr_state_machine);
-+              break;
-+      }
-+
-+      return 0;
-+}
-+
-+static int fsl_backplane_aneg_done(struct phy_device *phydev)
-+{
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+
-+      if (!phydev->mdio.dev.of_node) {
-+              dev_err(&phydev->mdio.dev, "No associated device tree node\n");
-+              return -EINVAL;
-+      }
-+      
-+      xgkr_inst->aneg_done = true;
-+
-+      return 1;
-+}
-+
-+static int fsl_backplane_config_aneg(struct phy_device *phydev)
-+{
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int i;
-+
-+      if (!phydev->mdio.dev.of_node) {
-+              dev_err(&phydev->mdio.dev, "No associated device tree node\n");
-+              return -EINVAL;
-+      }
-+
-+      switch (phydev->speed)
-+      {
-+      case SPEED_1000:
-+              phydev->supported |= SUPPORTED_1000baseKX_Full;
-+              start_1gkx_an(phydev);
-+              break;
-+
-+      case SPEED_10000:
-+              phydev->supported |= SUPPORTED_10000baseKR_Full;
-+              reset_lt(&xgkr_inst->xgkr[SINGLE_LANE]);
-+              start_xgkr_an(&xgkr_inst->xgkr[SINGLE_LANE]);
-+              /* start state machine*/
-+              start_xgkr_state_machine(&xgkr_inst->xgkr[SINGLE_LANE].xgkr_wk);
-+              break;
-+
-+      case SPEED_40000:
-+              phydev->supported |= SUPPORTED_40000baseKR4_Full;
-+              for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                      reset_lt(&xgkr_inst->xgkr[i]);
-+              }
-+              //Start AN only for Master Lane
-+              start_xgkr_an(&xgkr_inst->xgkr[MASTER_LANE]);
-+              /* start state machine*/
-+              for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                      start_xgkr_state_machine(&xgkr_inst->xgkr[i].xgkr_wk);
-+              }
-+              
-+              break;
-+      }
-+
-+      phydev->advertising = phydev->supported;
-+      phydev->duplex = 1;
-+
-+      return 0;
-+}
-+
-+static int fsl_backplane_suspend(struct phy_device *phydev)
-+{
-+      int i;
-+
-+      if (!phydev->mdio.dev.of_node) {
-+              dev_err(&phydev->mdio.dev, "No associated device tree node\n");
-+              return -EINVAL;
-+      }
-+
-+      if (phydev->speed == SPEED_10000 || phydev->speed == SPEED_40000) {
-+              struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+
-+              for (i = 0; i < xgkr_inst->phy_lanes; i++)
-+                      cancel_delayed_work_sync(&xgkr_inst->xgkr[i].xgkr_wk);
-+      }
-+      return 0;
-+}
-+
-+static int fsl_backplane_resume(struct phy_device *phydev)
-+{
-+      struct xgkr_phy_data *xgkr_inst = phydev->priv;
-+      int i;
-+
-+      if (!phydev->mdio.dev.of_node) {
-+              dev_err(&phydev->mdio.dev, "No associated device tree node\n");
-+              return -EINVAL;
-+      }
-+
-+      if (phydev->speed == SPEED_10000 || phydev->speed == SPEED_40000) {
-+              for (i = 0; i < xgkr_inst->phy_lanes; i++) {
-+                      init_xgkr(&xgkr_inst->xgkr[i], 1);
-+                      start_xgkr_state_machine(&xgkr_inst->xgkr[i].xgkr_wk);
-+              }
-+      }
-+      return 0;
-+}
-+
-+static int fsl_backplane_read_status(struct phy_device *phydev)
-+{
-+      if (!phydev->mdio.dev.of_node) {
-+              dev_err(&phydev->mdio.dev, "No associated device tree node\n");
-+              return -EINVAL;
-+      }
-+
-+      if (is_link_up(phydev))
-+              phydev->link = 1;
-+      else
-+              phydev->link = 0;
-+
-+      return 0;
-+}
-+
-+static int fsl_backplane_match_phy_device(struct phy_device *phydev)
-+{
-+      struct device_node *phy_node, *lane_node;
-+      const char *st;
-+      int serdes_type, i, ret;
-+      const int num_ids = ARRAY_SIZE(phydev->c45_ids.device_ids);
-+
-+      if (!phydev->mdio.dev.of_node) {
-+              return 0;
-+      }
-+
-+      //       WORKAROUND:
-+      // Required for LX2 devices
-+      // where PHY ID cannot be verified in PCS
-+      // because PCS Device Identifier Upper and Lower registers are hidden
-+      // and always return 0 when they are read:
-+      // 2  02        Device_ID0  RO          Bits 15:0       0
-+      // val = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x2);
-+      // 3  03        Device_ID1  RO          Bits 31:16      0
-+      // val = phy_read_mmd(phydev, MDIO_MMD_PCS, 0x3);
-+      //
-+      // To be removed: After the issue will be fixed on LX2 devices
-+
-+      if (!phydev->is_c45)
-+              return 0;
-+
-+      phy_node = phydev->mdio.dev.of_node;
-+
-+      lane_node = of_parse_phandle(phy_node, "fsl,lane-handle", 0);
-+      if (!lane_node) {
-+              dev_err(&phydev->mdio.dev, "parse fsl,lane-handle failed\n");
-+              return 0;
-+      }
-+
-+      ret = of_property_read_string(lane_node, "compatible", &st);
-+      if (ret < 0) {
-+              //assume SERDES-10G if compatible property is not specified
-+              serdes_type = SERDES_10G;
-+      }
-+      else if (!strcasecmp(st, "fsl,serdes-10g")) {
-+              serdes_type = SERDES_10G;
-+      } else if (!strcasecmp(st, "fsl,serdes-28g")) {
-+              serdes_type = SERDES_28G;
-+      } else {
-+              dev_err(&phydev->mdio.dev, "Unknown serdes-type\n");
-+              return 0;
-+      }
-+
-+      if (serdes_type == SERDES_10G) {
-+              //On LS devices we must find the c45 device with correct PHY ID
-+              //Implementation similar with the one existent in phy_device: @function: phy_bus_match
-+              for (i = 1; i < num_ids; i++) {
-+                      if (!(phydev->c45_ids.devices_in_package & (1 << i)))
-+                              continue;
-+
-+                      if ((PCS_PHY_DEVICE_ID & PCS_PHY_DEVICE_ID_MASK) ==
-+                              (phydev->c45_ids.device_ids[i] & PCS_PHY_DEVICE_ID_MASK))
-+                      {
-+                              return 1;
-+                      }
-+              }
-+              return 0;
-+      }
-+
-+      //On LX devices we cannot verify PHY ID
-+      //so we are happy only with preliminary verifications already made: mdio.dev.of_node and is_c45
-+      //because we already filtered other undesired devices: non clause 45
-+
-+      return 1;
-+}
-+
-+static struct phy_driver fsl_backplane_driver[] = {
-+      {
-+      .phy_id         = PCS_PHY_DEVICE_ID,
-+      .name           = "Freescale Backplane",
-+      .phy_id_mask    = PCS_PHY_DEVICE_ID_MASK,
-+      .features       = SUPPORTED_Backplane | SUPPORTED_Autoneg |
-+                        SUPPORTED_MII,
-+      .probe          = fsl_backplane_probe,
-+      .aneg_done      = fsl_backplane_aneg_done,
-+      .config_aneg    = fsl_backplane_config_aneg,
-+      .read_status    = fsl_backplane_read_status,
-+      .suspend        = fsl_backplane_suspend,
-+      .resume         = fsl_backplane_resume,
-+      .match_phy_device = fsl_backplane_match_phy_device,
-+      },
-+};
-+
-+module_phy_driver(fsl_backplane_driver);
-+
-+static struct mdio_device_id __maybe_unused freescale_tbl[] = {
-+      { PCS_PHY_DEVICE_ID, PCS_PHY_DEVICE_ID_MASK },
-+      { }
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, freescale_tbl);
-+
-+MODULE_DESCRIPTION("Freescale Backplane driver");
-+MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/drivers/net/phy/fsl_backplane.h
-@@ -0,0 +1,41 @@
-+/* SPDX-License-Identifier: GPL-2.0+ */
-+/*
-+ *  DPAA backplane driver.
-+ *   Author: Florinel Iordache <florinel.iordache@nxp.com>
-+ *
-+ * Copyright 2018 NXP
-+ *
-+ * Licensed under the GPL-2 or later.
-+ */
-+
-+#ifndef FSL_BACKPLANE_H
-+#define FSL_BACKPLANE_H
-+
-+/* C(-1) */
-+#define BIN_M1                                                0
-+/* C(1) */
-+#define BIN_LONG                                      1
-+
-+#define BIN_SNAPSHOT_NUM                      5
-+#define BIN_M1_THRESHOLD                      3
-+#define BIN_LONG_THRESHOLD                    2
-+
-+struct serdes_access {
-+
-+      int serdes_type;
-+      bool is_little_endian;
-+      u32 (*ioread32)(u32 *reg);
-+      void (*iowrite32)(u32 value, u32 *reg);
-+      u32 (*get_lane_memmap_size)(void);
-+      void (*tune_tecr)(void *reg, u32 ratio_preq, u32 ratio_pst1q, u32 adpt_eq, bool reset);
-+      void (*reset_lane)(void *reg);
-+      void (*lane_set_1gkx)(void *reg);
-+      int (*get_median_gaink2)(u32 *reg);
-+      bool (*is_bin_early)(int bin_sel, void *reg);
-+};
-+
-+struct serdes_access* setup_serdes_access_10g(void);
-+struct serdes_access* setup_serdes_access_28g(void);
-+
-+
-+#endif //FSL_BACKPLANE_H
---- /dev/null
-+++ b/drivers/net/phy/fsl_backplane_serdes_10g.c
-@@ -0,0 +1,281 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ *  DPAA backplane driver for SerDes 10G.
-+ *   Author: Florinel Iordache <florinel.iordache@nxp.com>
-+ *
-+ * Copyright 2018 NXP
-+ *
-+ * Licensed under the GPL-2 or later.
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+
-+#include "fsl_backplane.h"
-+
-+#define BIN_M1_SEL                                    6
-+#define BIN_Long_SEL                          7
-+#define CDR_SEL_MASK                          0x00070000
-+
-+#define PRE_COE_SHIFT                         22
-+#define POST_COE_SHIFT                                16
-+#define ZERO_COE_SHIFT                                8
-+
-+#define TECR0_INIT                                    0x24200000
-+
-+#define GCR0_RESET_MASK                               0x00600000
-+
-+#define GCR1_SNP_START_MASK                   0x00000040
-+#define GCR1_CTL_SNP_START_MASK               0x00002000
-+
-+#define RECR1_CTL_SNP_DONE_MASK               0x00000002
-+#define RECR1_SNP_DONE_MASK                   0x00000004
-+#define TCSR1_SNP_DATA_MASK                   0x0000ffc0
-+#define TCSR1_SNP_DATA_SHIFT          6
-+#define TCSR1_EQ_SNPBIN_SIGN_MASK     0x100
-+
-+#define RECR1_GAINK2_MASK                     0x0f000000
-+#define RECR1_GAINK2_SHIFT                    24
-+
-+/* Required only for 1000BASE KX */
-+#define GCR1_REIDL_TH_MASK                    0x00700000
-+#define GCR1_REIDL_EX_SEL_MASK                0x000c0000
-+#define GCR1_REIDL_ET_MAS_MASK                0x00004000
-+#define TECR0_AMP_RED_MASK                    0x0000003f
-+
-+struct per_lane_ctrl_status {
-+      u32 gcr0;       /* 0x.000 - General Control Register 0 */
-+      u32 gcr1;       /* 0x.004 - General Control Register 1 */
-+      u32 gcr2;       /* 0x.008 - General Control Register 2 */
-+      u32 resv1;      /* 0x.00C - Reserved */
-+      u32 recr0;      /* 0x.010 - Receive Equalization Control Register 0 */
-+      u32 recr1;      /* 0x.014 - Receive Equalization Control Register 1 */
-+      u32 tecr0;      /* 0x.018 - Transmit Equalization Control Register 0 */
-+      u32 resv2;      /* 0x.01C - Reserved */
-+      u32 tlcr0;      /* 0x.020 - TTL Control Register 0 */
-+      u32 tlcr1;      /* 0x.024 - TTL Control Register 1 */
-+      u32 tlcr2;      /* 0x.028 - TTL Control Register 2 */
-+      u32 tlcr3;      /* 0x.02C - TTL Control Register 3 */
-+      u32 tcsr0;      /* 0x.030 - Test Control/Status Register 0 */
-+      u32 tcsr1;      /* 0x.034 - Test Control/Status Register 1 */
-+      u32 tcsr2;      /* 0x.038 - Test Control/Status Register 2 */
-+      u32 tcsr3;      /* 0x.03C - Test Control/Status Register 3 */
-+};
-+
-+static struct serdes_access srds;
-+
-+static u32 get_lane_memmap_size(void)
-+{
-+      return 0x40;
-+}
-+
-+static void reset_lane(void *reg)
-+{
-+      struct per_lane_ctrl_status *reg_base = reg;
-+
-+      /* reset the lane */
-+      srds.iowrite32(srds.ioread32(&reg_base->gcr0) & ~GCR0_RESET_MASK,
-+                  &reg_base->gcr0);
-+      udelay(1);
-+      
-+      /* unreset the lane */
-+      srds.iowrite32(srds.ioread32(&reg_base->gcr0) | GCR0_RESET_MASK,
-+                  &reg_base->gcr0);
-+      udelay(1);
-+}
-+
-+static void tune_tecr(void *reg, u32 ratio_preq, u32 ratio_pst1q, u32 adpt_eq, bool reset)
-+{
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      u32 val;
-+
-+      val = TECR0_INIT |
-+              adpt_eq << ZERO_COE_SHIFT |
-+              ratio_preq << PRE_COE_SHIFT |
-+              ratio_pst1q << POST_COE_SHIFT;
-+
-+      if (reset) {
-+              /* reset the lane */
-+              srds.iowrite32(srds.ioread32(&reg_base->gcr0) & ~GCR0_RESET_MASK,
-+                              &reg_base->gcr0);
-+              udelay(1);
-+      }
-+      
-+      srds.iowrite32(val, &reg_base->tecr0);
-+      udelay(1);
-+      
-+      if (reset) {
-+              /* unreset the lane */
-+              srds.iowrite32(srds.ioread32(&reg_base->gcr0) | GCR0_RESET_MASK,
-+                              &reg_base->gcr0);
-+              udelay(1);
-+      }
-+}
-+
-+static void lane_set_1gkx(void *reg)
-+{
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      u32 val;
-+
-+      /* reset the lane */
-+      srds.iowrite32(srds.ioread32(&reg_base->gcr0) & ~GCR0_RESET_MASK,
-+                  &reg_base->gcr0);
-+      udelay(1);
-+
-+      /* set gcr1 for 1GKX */
-+      val = srds.ioread32(&reg_base->gcr1);
-+      val &= ~(GCR1_REIDL_TH_MASK | GCR1_REIDL_EX_SEL_MASK |
-+               GCR1_REIDL_ET_MAS_MASK);
-+      srds.iowrite32(val, &reg_base->gcr1);
-+      udelay(1);
-+
-+      /* set tecr0 for 1GKX */
-+      val = srds.ioread32(&reg_base->tecr0);
-+      val &= ~TECR0_AMP_RED_MASK;
-+      srds.iowrite32(val, &reg_base->tecr0);
-+      udelay(1);
-+
-+      /* unreset the lane */
-+      srds.iowrite32(srds.ioread32(&reg_base->gcr0) | GCR0_RESET_MASK,
-+                  &reg_base->gcr0);
-+      udelay(1);
-+}
-+
-+static int get_median_gaink2(u32 *reg)
-+{
-+      int gaink2_snap_shot[BIN_SNAPSHOT_NUM];
-+      u32 rx_eq_snp;
-+      struct per_lane_ctrl_status *reg_base;
-+      int timeout;
-+      int i, j, tmp, pos;
-+
-+      reg_base = (struct per_lane_ctrl_status *)reg;
-+
-+      for (i = 0; i < BIN_SNAPSHOT_NUM; i++) {
-+              /* wait RECR1_CTL_SNP_DONE_MASK has cleared */
-+              timeout = 100;
-+              while (srds.ioread32(&reg_base->recr1) &
-+                     RECR1_CTL_SNP_DONE_MASK) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* start snap shot */
-+              srds.iowrite32((srds.ioread32(&reg_base->gcr1) |
-+                          GCR1_CTL_SNP_START_MASK),
-+                          &reg_base->gcr1);
-+
-+              /* wait for SNP done */
-+              timeout = 100;
-+              while (!(srds.ioread32(&reg_base->recr1) &
-+                     RECR1_CTL_SNP_DONE_MASK)) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* read and save the snap shot */
-+              rx_eq_snp = srds.ioread32(&reg_base->recr1);
-+              gaink2_snap_shot[i] = (rx_eq_snp & RECR1_GAINK2_MASK) >>
-+                                      RECR1_GAINK2_SHIFT;
-+
-+              /* terminate the snap shot by setting GCR1[REQ_CTL_SNP] */
-+              srds.iowrite32((srds.ioread32(&reg_base->gcr1) &
-+                          ~GCR1_CTL_SNP_START_MASK),
-+                          &reg_base->gcr1);
-+      }
-+
-+      /* get median of the 5 snap shot */
-+      for (i = 0; i < BIN_SNAPSHOT_NUM - 1; i++) {
-+              tmp = gaink2_snap_shot[i];
-+              pos = i;
-+              for (j = i + 1; j < BIN_SNAPSHOT_NUM; j++) {
-+                      if (gaink2_snap_shot[j] < tmp) {
-+                              tmp = gaink2_snap_shot[j];
-+                              pos = j;
-+                      }
-+              }
-+
-+              gaink2_snap_shot[pos] = gaink2_snap_shot[i];
-+              gaink2_snap_shot[i] = tmp;
-+      }
-+
-+      return gaink2_snap_shot[2];
-+}
-+
-+static bool is_bin_early(int bin_sel, void *reg)
-+{
-+      bool early = false;
-+      int bin_snap_shot[BIN_SNAPSHOT_NUM];
-+      int i, negative_count = 0;
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      int timeout;
-+
-+      for (i = 0; i < BIN_SNAPSHOT_NUM; i++) {
-+              /* wait RECR1_SNP_DONE_MASK has cleared */
-+              timeout = 100;
-+              while ((srds.ioread32(&reg_base->recr1) & RECR1_SNP_DONE_MASK)) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* set TCSR1[CDR_SEL] to BinM1/BinLong */
-+              if (bin_sel == BIN_M1) {
-+                      srds.iowrite32((srds.ioread32(&reg_base->tcsr1) &
-+                                  ~CDR_SEL_MASK) | BIN_M1_SEL,
-+                                  &reg_base->tcsr1);
-+              } else {
-+                      srds.iowrite32((srds.ioread32(&reg_base->tcsr1) &
-+                                  ~CDR_SEL_MASK) | BIN_Long_SEL,
-+                                  &reg_base->tcsr1);
-+              }
-+
-+              /* start snap shot */
-+              srds.iowrite32(srds.ioread32(&reg_base->gcr1) | GCR1_SNP_START_MASK,
-+                          &reg_base->gcr1);
-+
-+              /* wait for SNP done */
-+              timeout = 100;
-+              while (!(srds.ioread32(&reg_base->recr1) & RECR1_SNP_DONE_MASK)) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* read and save the snap shot */
-+              bin_snap_shot[i] = (srds.ioread32(&reg_base->tcsr1) &
-+                              TCSR1_SNP_DATA_MASK) >> TCSR1_SNP_DATA_SHIFT;
-+              if (bin_snap_shot[i] & TCSR1_EQ_SNPBIN_SIGN_MASK)
-+                      negative_count++;
-+
-+              /* terminate the snap shot by setting GCR1[REQ_CTL_SNP] */
-+              srds.iowrite32(srds.ioread32(&reg_base->gcr1) & ~GCR1_SNP_START_MASK,
-+                          &reg_base->gcr1);
-+      }
-+
-+      if (((bin_sel == BIN_M1) && (negative_count > BIN_M1_THRESHOLD)) ||
-+          ((bin_sel == BIN_LONG && (negative_count > BIN_LONG_THRESHOLD)))) {
-+              early = true;
-+      }
-+
-+      return early;
-+}
-+
-+struct serdes_access* setup_serdes_access_10g(void)
-+{
-+      srds.get_lane_memmap_size = get_lane_memmap_size;
-+      srds.tune_tecr = tune_tecr;
-+      srds.reset_lane = reset_lane;
-+      srds.lane_set_1gkx = lane_set_1gkx;
-+      srds.get_median_gaink2 = get_median_gaink2;
-+      srds.is_bin_early = is_bin_early;
-+
-+      return &srds;
-+}
-+
---- /dev/null
-+++ b/drivers/net/phy/fsl_backplane_serdes_28g.c
-@@ -0,0 +1,336 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/*
-+ *  DPAA backplane driver for SerDes 28G.
-+ *   Author: Florinel Iordache <florinel.iordache@nxp.com>
-+ *
-+ * Copyright 2018 NXP
-+ *
-+ * Licensed under the GPL-2 or later.
-+ */
-+
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+#include <linux/sched.h>
-+
-+#include "fsl_backplane.h"
-+
-+#define BIN_M1_SEL                                    0x0000c000
-+#define BIN_Long_SEL                          0x0000d000
-+#define CDR_SEL_MASK                          0x0000f000
-+
-+#define PRE_COE_SHIFT                         16
-+#define POST_COE_SHIFT                                8
-+#define ZERO_COE_SHIFT                                24
-+
-+#define TECR0_INIT                                    0x20808000
-+
-+#define RESET_REQ_MASK                                0x80000000
-+
-+#define RECR3_SNP_START_MASK          0x80000000
-+#define RECR3_SNP_DONE_MASK                   0x40000000
-+
-+#define RECR4_SNP_DATA_MASK                   0x000003ff
-+#define RECR4_SNP_DATA_SHIFT          0
-+#define RECR4_EQ_SNPBIN_SIGN_MASK     0x200
-+
-+#define RECR3_GAINK2_MASK                     0x1f000000
-+#define RECR3_GAINK2_SHIFT                    24
-+
-+/* Required only for 1000BASE KX */
-+#define GCR1_REIDL_TH_MASK                    0x00700000
-+#define GCR1_REIDL_EX_SEL_MASK                0x000c0000
-+#define GCR1_REIDL_ET_MAS_MASK                0x04000000
-+#define TECR0_AMP_RED_MASK                    0x0000003f
-+
-+struct per_lane_ctrl_status {
-+      u32 gcr0;       /* 0x.000 - General Control Register 0 */
-+      u32 resv1;      /* 0x.004 - Reserved */
-+      u32 resv2;      /* 0x.008 - Reserved */
-+      u32 resv3;      /* 0x.00C - Reserved */
-+      u32 resv4;      /* 0x.010 - Reserved */
-+      u32 resv5;      /* 0x.014 - Reserved */
-+      u32 resv6;      /* 0x.018 - Reserved */
-+      u32 resv7;      /* 0x.01C - Reserved */
-+      u32 trstctl;    /* 0x.020 - TX Reset Control Register */
-+      u32 tgcr0;      /* 0x.024 - TX General Control Register 0 */
-+      u32 tgcr1;      /* 0x.028 - TX General Control Register 1 */
-+      u32 tgcr2;      /* 0x.02C - TX General Control Register 2 */
-+      u32 tecr0;      /* 0x.030 - Transmit Equalization Control Register 0 */
-+      u32 tecr1;      /* 0x.034 - Transmit Equalization Control Register 1 */
-+      u32 resv8;      /* 0x.038 - Reserved */
-+      u32 resv9;      /* 0x.03C - Reserved */
-+      u32 rrstctl;    /* 0x.040 - RX Reset Control Register */
-+      u32 rgcr0;      /* 0x.044 - RX General Control Register 0 */
-+      u32 rxgcr1;     /* 0x.048 - RX General Control Register 1 */
-+      u32 resv10;     /* 0x.04C - Reserved */
-+      u32 recr0;      /* 0x.050 - RX Equalization Register 0 */
-+      u32 recr1;      /* 0x.054 - RX Equalization Register 1 */
-+      u32 recr2;      /* 0x.058 - RX Equalization Register 2 */
-+      u32 recr3;      /* 0x.05C - RX Equalization Register 3 */
-+      u32 recr4;      /* 0x.060 - RX Equalization Register 4 */
-+      u32 resv11;     /* 0x.064 - Reserved */
-+      u32 rccr0;      /* 0x.068 - RX Calibration Register 0 */
-+      u32 rccr1;      /* 0x.06C - RX Calibration Register 1 */
-+      u32 rcpcr0;     /* 0x.070 - RX Clock Path Register 0 */
-+      u32 rsccr0;     /* 0x.074 - RX Sampler Calibration Control Register 0 */
-+      u32 rsccr1;     /* 0x.078 - RX Sampler Calibration Control Register 1 */
-+      u32 resv12;     /* 0x.07C - Reserved */
-+      u32 ttlcr0;     /* 0x.080 - Transition Tracking Loop Register 0 */
-+      u32 ttlcr1;     /* 0x.084 - Transition Tracking Loop Register 1 */
-+      u32 ttlcr2;     /* 0x.088 - Transition Tracking Loop Register 2 */
-+      u32 ttlcr3;     /* 0x.08C - Transition Tracking Loop Register 3 */
-+      u32 resv13;     /* 0x.090 - Reserved */
-+      u32 resv14;     /* 0x.094 - Reserved */
-+      u32 resv15;     /* 0x.098 - Reserved */
-+      u32 resv16;     /* 0x.09C - Reserved */
-+      u32 tcsr0;      /* 0x.0A0 - Test Control/Status Register 0 */
-+      u32 tcsr1;      /* 0x.0A4 - Test Control/Status Register 1 */
-+      u32 tcsr2;      /* 0x.0A8 - Test Control/Status Register 2 */
-+      u32 tcsr3;      /* 0x.0AC - Test Control/Status Register 3 */
-+      u32 tcsr4;      /* 0x.0B0 - Test Control/Status Register 4 */
-+      u32 resv17;     /* 0x.0B4 - Reserved */
-+      u32 resv18;     /* 0x.0B8 - Reserved */
-+      u32 resv19;     /* 0x.0BC - Reserved */
-+      u32 rxcb0;      /* 0x.0C0 - RX Control Block Register 0 */
-+      u32 rxcb1;      /* 0x.0C4 - RX Control Block Register 1 */
-+      u32 resv20;     /* 0x.0C8 - Reserved */
-+      u32 resv21;     /* 0x.0CC - Reserved */
-+      u32 rxss0;      /* 0x.0D0 - RX Speed Switch Register 0 */
-+      u32 rxss1;      /* 0x.0D4 - RX Speed Switch Register 1 */
-+      u32 rxss2;      /* 0x.0D8 - RX Speed Switch Register 2 */
-+      u32 resv22;     /* 0x.0DC - Reserved */
-+      u32 txcb0;      /* 0x.0E0 - TX Control Block Register 0 */
-+      u32 txcb1;      /* 0x.0E4 - TX Control Block Register 1 */
-+      u32 resv23;     /* 0x.0E8 - Reserved */
-+      u32 resv24;     /* 0x.0EC - Reserved */
-+      u32 txss0;      /* 0x.0F0 - TX Speed Switch Register 0 */
-+      u32 txss1;      /* 0x.0F4 - TX Speed Switch Register 1 */
-+      u32 txss2;      /* 0x.0F8 - TX Speed Switch Register 2 */
-+      u32 resv25;     /* 0x.0FC - Reserved */
-+};
-+
-+static struct serdes_access srds;
-+
-+static u32 get_lane_memmap_size(void)
-+{
-+      return 0x100;
-+}
-+
-+static void reset_lane(void *reg)
-+{
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      u32 val;
-+      unsigned long timeout;
-+
-+      /* reset Tx lane: send reset request */
-+      srds.iowrite32(srds.ioread32(&reg_base->trstctl) | RESET_REQ_MASK,
-+                  &reg_base->trstctl);
-+      udelay(1);
-+      timeout = 10;
-+      while (timeout--) {
-+              val = srds.ioread32(&reg_base->trstctl);
-+              if (!(val & RESET_REQ_MASK))
-+                      break;
-+              usleep_range(5, 20);
-+      }
-+      
-+      /* reset Rx lane: send reset request */
-+      srds.iowrite32(srds.ioread32(&reg_base->rrstctl) | RESET_REQ_MASK,
-+                  &reg_base->rrstctl);
-+      udelay(1);
-+      timeout = 10;
-+      while (timeout--) {
-+              val = srds.ioread32(&reg_base->rrstctl);
-+              if (!(val & RESET_REQ_MASK))
-+                      break;
-+              usleep_range(5, 20);
-+      }
-+      
-+      /* wait for a while after reset */
-+      timeout = jiffies + 10;
-+      while (time_before(jiffies, timeout)) {
-+              schedule();
-+              usleep_range(5, 20);
-+      }
-+}
-+
-+static void tune_tecr(void *reg, u32 ratio_preq, u32 ratio_pst1q, u32 adpt_eq, bool reset)
-+{
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      u32 val;
-+
-+      if (reset) {
-+              /* reset lanes */
-+              reset_lane(reg);
-+      }
-+      
-+      val = TECR0_INIT |
-+              ratio_preq << PRE_COE_SHIFT |
-+              ratio_pst1q << POST_COE_SHIFT;
-+      srds.iowrite32(val, &reg_base->tecr0);
-+
-+      val = adpt_eq << ZERO_COE_SHIFT;
-+      srds.iowrite32(val, &reg_base->tecr1);
-+      
-+      udelay(1);
-+}
-+
-+static void lane_set_1gkx(void *reg)
-+{
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      u32 val;
-+
-+      /* reset lanes */
-+      reset_lane(reg);
-+
-+      /* set gcr1 for 1GKX */
-+      val = srds.ioread32(&reg_base->rxgcr1);
-+      val &= ~(GCR1_REIDL_TH_MASK | GCR1_REIDL_EX_SEL_MASK |
-+               GCR1_REIDL_ET_MAS_MASK);
-+      srds.iowrite32(val, &reg_base->rxgcr1);
-+      udelay(1);
-+
-+      /* set tecr0 for 1GKX */
-+      val = srds.ioread32(&reg_base->tecr0);
-+      val &= ~TECR0_AMP_RED_MASK;
-+      srds.iowrite32(val, &reg_base->tecr0);
-+      udelay(1);
-+}
-+
-+static int get_median_gaink2(u32 *reg)
-+{
-+      int gaink2_snap_shot[BIN_SNAPSHOT_NUM];
-+      u32 rx_eq_snp;
-+      struct per_lane_ctrl_status *reg_base;
-+      int timeout;
-+      int i, j, tmp, pos;
-+
-+      reg_base = (struct per_lane_ctrl_status *)reg;
-+
-+      for (i = 0; i < BIN_SNAPSHOT_NUM; i++) {
-+              /* wait RECR3_SNP_DONE_MASK has cleared */
-+              timeout = 100;
-+              while (srds.ioread32(&reg_base->recr3) &
-+                              RECR3_SNP_DONE_MASK) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* start snap shot */
-+              srds.iowrite32((srds.ioread32(&reg_base->recr3) |
-+                          RECR3_SNP_START_MASK),
-+                          &reg_base->recr3);
-+
-+              /* wait for SNP done */
-+              timeout = 100;
-+              while (!(srds.ioread32(&reg_base->recr3) &
-+                              RECR3_SNP_DONE_MASK)) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* read and save the snap shot */
-+              rx_eq_snp = srds.ioread32(&reg_base->recr3);
-+              gaink2_snap_shot[i] = (rx_eq_snp & RECR3_GAINK2_MASK) >>
-+                                      RECR3_GAINK2_SHIFT;
-+
-+              /* terminate the snap shot by setting GCR1[REQ_CTL_SNP] */
-+              srds.iowrite32((srds.ioread32(&reg_base->recr3) &
-+                          ~RECR3_SNP_START_MASK),
-+                          &reg_base->recr3);
-+      }
-+
-+      /* get median of the 5 snap shot */
-+      for (i = 0; i < BIN_SNAPSHOT_NUM - 1; i++) {
-+              tmp = gaink2_snap_shot[i];
-+              pos = i;
-+              for (j = i + 1; j < BIN_SNAPSHOT_NUM; j++) {
-+                      if (gaink2_snap_shot[j] < tmp) {
-+                              tmp = gaink2_snap_shot[j];
-+                              pos = j;
-+                      }
-+              }
-+
-+              gaink2_snap_shot[pos] = gaink2_snap_shot[i];
-+              gaink2_snap_shot[i] = tmp;
-+      }
-+
-+      return gaink2_snap_shot[2];
-+}
-+
-+static bool is_bin_early(int bin_sel, void *reg)
-+{
-+      bool early = false;
-+      int bin_snap_shot[BIN_SNAPSHOT_NUM];
-+      int i, negative_count = 0;
-+      struct per_lane_ctrl_status *reg_base = reg;
-+      int timeout;
-+
-+      for (i = 0; i < BIN_SNAPSHOT_NUM; i++) {
-+              /* wait RECR3_SNP_DONE_MASK has cleared */
-+              timeout = 100;
-+              while ((srds.ioread32(&reg_base->recr3) & RECR3_SNP_DONE_MASK)) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* set TCSR1[CDR_SEL] to BinM1/BinLong */
-+              if (bin_sel == BIN_M1) {
-+                      srds.iowrite32((srds.ioread32(&reg_base->recr4) &
-+                                  ~CDR_SEL_MASK) | BIN_M1_SEL,
-+                                  &reg_base->recr4);
-+              } else {
-+                      srds.iowrite32((srds.ioread32(&reg_base->recr4) &
-+                                  ~CDR_SEL_MASK) | BIN_Long_SEL,
-+                                  &reg_base->recr4);
-+              }
-+
-+              /* start snap shot */
-+              srds.iowrite32(srds.ioread32(&reg_base->recr3) | RECR3_SNP_START_MASK,
-+                          &reg_base->recr3);
-+
-+              /* wait for SNP done */
-+              timeout = 100;
-+              while (!(srds.ioread32(&reg_base->recr3) & RECR3_SNP_DONE_MASK)) {
-+                      udelay(1);
-+                      timeout--;
-+                      if (timeout == 0)
-+                              break;
-+              }
-+
-+              /* read and save the snap shot */
-+              bin_snap_shot[i] = (srds.ioread32(&reg_base->recr4) &
-+                              RECR4_SNP_DATA_MASK) >> RECR4_SNP_DATA_SHIFT;
-+              if (bin_snap_shot[i] & RECR4_EQ_SNPBIN_SIGN_MASK)
-+                      negative_count++;
-+
-+              /* terminate the snap shot by setting GCR1[REQ_CTL_SNP] */
-+              srds.iowrite32(srds.ioread32(&reg_base->recr3) & ~RECR3_SNP_START_MASK,
-+                          &reg_base->recr3);
-+      }
-+
-+      if (((bin_sel == BIN_M1) && (negative_count > BIN_M1_THRESHOLD)) ||
-+          ((bin_sel == BIN_LONG && (negative_count > BIN_LONG_THRESHOLD)))) {
-+              early = true;
-+      }
-+
-+      return early;
-+}
-+
-+struct serdes_access* setup_serdes_access_28g(void)
-+{
-+      srds.get_lane_memmap_size = get_lane_memmap_size;
-+      srds.tune_tecr = tune_tecr;
-+      srds.reset_lane = reset_lane;
-+      srds.lane_set_1gkx = lane_set_1gkx;
-+      srds.get_median_gaink2 = get_median_gaink2;
-+      srds.is_bin_early = is_bin_early;
-+
-+      return &srds;
-+}
---- /dev/null
-+++ b/drivers/net/phy/inphi.c
-@@ -0,0 +1,594 @@
-+/*
-+ * Copyright 2018 NXP
-+ * Copyright 2018 INPHI
-+ *
-+ * Redistribution and use in source and binary forms, with or without
-+ * modification, are permitted provided that the following conditions are met:
-+ *
-+ * 1. Redistributions of source code must retain the above copyright notice,
-+ * this list of conditions and the following disclaimer.
-+ * 2. Redistributions in binary form must reproduce the above copyright notice,
-+ * this list of conditions and the following disclaimer in the documentation
-+ * and/or other materials provided with the distribution.
-+ *
-+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-+ * POSSIBILITY OF SUCH DAMAGE.
-+ *
-+ * Inphi is a registered trademark of Inphi Corporation
-+ *
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/phy.h>
-+#include <linux/mdio.h>
-+#include <linux/interrupt.h>
-+#include <linux/platform_device.h>
-+#include <linux/of_irq.h>
-+#include <linux/workqueue.h>
-+#include <linux/i2c.h>
-+#include <linux/timer.h>
-+#include <linux/delay.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/fs.h>
-+#include <linux/cdev.h>
-+#include <linux/device.h>
-+#include <linux/slab.h>
-+#include <linux/uaccess.h>
-+
-+#define PHY_ID_IN112525  0x02107440
-+
-+#define INPHI_S03_DEVICE_ID_MSB 0x2
-+#define INPHI_S03_DEVICE_ID_LSB 0x3
-+
-+#define ALL_LANES             4
-+#define INPHI_POLL_DELAY      2500
-+
-+#define PHYCTRL_REG1  0x0012
-+#define PHYCTRL_REG2  0x0014
-+#define PHYCTRL_REG3  0x0120
-+#define PHYCTRL_REG4  0x0121
-+#define PHYCTRL_REG5  0x0180
-+#define PHYCTRL_REG6  0x0580
-+#define PHYCTRL_REG7  0x05C4
-+#define PHYCTRL_REG8  0x01C8
-+#define PHYCTRL_REG9  0x0521
-+
-+#define PHYSTAT_REG1  0x0021
-+#define PHYSTAT_REG2  0x0022
-+#define PHYSTAT_REG3  0x0123
-+
-+#define PHYMISC_REG1  0x0025
-+#define PHYMISC_REG2  0x002c
-+#define PHYMISC_REG3  0x00b3
-+#define PHYMISC_REG4  0x0181
-+#define PHYMISC_REG5  0x019D
-+#define PHYMISC_REG6  0x0198
-+#define PHYMISC_REG7  0x0199
-+#define PHYMISC_REG8  0x0581
-+#define PHYMISC_REG9  0x0598
-+#define PHYMISC_REG10 0x059c
-+#define PHYMISC_REG20 0x01B0
-+#define PHYMISC_REG21 0x01BC
-+#define PHYMISC_REG22 0x01C0
-+
-+#define RX_VCO_CODE_OFFSET    5
-+#define VCO_CODE              390
-+
-+int vco_codes[ALL_LANES] = {
-+      VCO_CODE,
-+      VCO_CODE,
-+      VCO_CODE,
-+      VCO_CODE
-+};
-+
-+static void mykmod_work_handler(struct work_struct *w);
-+
-+static struct workqueue_struct *wq;
-+static DECLARE_DELAYED_WORK(mykmod_work, mykmod_work_handler);
-+static unsigned long onesec;
-+struct phy_device *inphi_phydev;
-+
-+static int mdio_wr(u32 regnum, u16 val)
-+{
-+      regnum = MII_ADDR_C45 | (MDIO_MMD_VEND1 << 16) | (regnum & 0xffff);
-+
-+      return mdiobus_write(inphi_phydev->mdio.bus, inphi_phydev->mdio.addr,
-+                              regnum, val);
-+}
-+
-+static int mdio_rd(u32 regnum)
-+{
-+      regnum = MII_ADDR_C45 | (MDIO_MMD_VEND1 << 16) | (regnum & 0xffff);
-+
-+      return mdiobus_read(inphi_phydev->mdio.bus, inphi_phydev->mdio.addr,
-+                              regnum);
-+}
-+
-+
-+int bit_test(int value, int bit_field)
-+{
-+      int result;
-+      int bit_mask = (1 << bit_field);
-+
-+      result = ((value & bit_mask) == bit_mask);
-+      return result;
-+}
-+
-+int tx_pll_lock_test(int lane)
-+{
-+      int i, val, locked = 1;
-+
-+      if (lane == ALL_LANES) {
-+              for (i = 0; i < ALL_LANES; i++) {
-+                      val = mdio_rd(i * 0x100 + PHYSTAT_REG3);
-+                      locked = locked & bit_test(val, 15);
-+              }
-+      } else {
-+              val = mdio_rd(lane * 0x100 + PHYSTAT_REG3);
-+              locked = locked & bit_test(val, 15);
-+      }
-+
-+      return locked;
-+}
-+
-+void rx_reset_assert(int lane)
-+{
-+      int mask, val;
-+
-+      if (lane == ALL_LANES) {
-+              val = mdio_rd(PHYMISC_REG2);
-+              mask = (1 << 15);
-+              mdio_wr(PHYMISC_REG2, val + mask);
-+      } else {
-+              val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+              mask = (1 << 6);
-+              mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
-+      }
-+}
-+
-+void rx_reset_de_assert(int lane)
-+{
-+      int mask, val;
-+
-+      if (lane == ALL_LANES) {
-+              val = mdio_rd(PHYMISC_REG2);
-+              mask = 0xffff - (1 << 15);
-+              mdio_wr(PHYMISC_REG2, val & mask);
-+      } else {
-+              val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+              mask = 0xffff - (1 << 6);
-+              mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
-+      }
-+}
-+
-+void rx_powerdown_assert(int lane)
-+{
-+      int mask, val;
-+
-+      val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+      mask = (1 << 5);
-+      mdio_wr(lane * 0x100 + PHYCTRL_REG8, val + mask);
-+}
-+
-+void rx_powerdown_de_assert(int lane)
-+{
-+      int mask, val;
-+
-+      val = mdio_rd(lane * 0x100 + PHYCTRL_REG8);
-+      mask = 0xffff - (1 << 5);
-+      mdio_wr(lane * 0x100 + PHYCTRL_REG8, val & mask);
-+}
-+
-+void tx_pll_assert(int lane)
-+{
-+      int val, recal;
-+
-+      if (lane == ALL_LANES) {
-+              val = mdio_rd(PHYMISC_REG2);
-+              recal = (1 << 12);
-+              mdio_wr(PHYMISC_REG2, val | recal);
-+      } else {
-+              val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
-+              recal = (1 << 15);
-+              mdio_wr(lane * 0x100 + PHYCTRL_REG4, val | recal);
-+      }
-+}
-+
-+void tx_pll_de_assert(int lane)
-+{
-+      int recal, val;
-+
-+      if (lane == ALL_LANES) {
-+              val = mdio_rd(PHYMISC_REG2);
-+              recal = 0xefff;
-+              mdio_wr(PHYMISC_REG2, val & recal);
-+      } else {
-+              val = mdio_rd(lane * 0x100 + PHYCTRL_REG4);
-+              recal = 0x7fff;
-+              mdio_wr(lane * 0x100 + PHYCTRL_REG4, val & recal);
-+      }
-+}
-+
-+void tx_core_assert(int lane)
-+{
-+      int recal, val, val2, core_reset;
-+
-+      if (lane == 4) {
-+              val = mdio_rd(PHYMISC_REG2);
-+              recal = 1 << 10;
-+              mdio_wr(PHYMISC_REG2, val | recal);
-+      } else {
-+              val2 = mdio_rd(PHYMISC_REG3);
-+              core_reset = (1 << (lane + 8));
-+              mdio_wr(PHYMISC_REG3, val2 | core_reset);
-+      }
-+}
-+
-+void lol_disable(int lane)
-+{
-+      int val, mask;
-+
-+      val = mdio_rd(PHYMISC_REG3);
-+      mask = 1 << (lane + 4);
-+      mdio_wr(PHYMISC_REG3, val | mask);
-+}
-+
-+void tx_core_de_assert(int lane)
-+{
-+      int val, recal, val2, core_reset;
-+
-+      if (lane == ALL_LANES) {
-+              val = mdio_rd(PHYMISC_REG2);
-+              recal = 0xffff - (1 << 10);
-+              mdio_wr(PHYMISC_REG2, val & recal);
-+      } else {
-+              val2 = mdio_rd(PHYMISC_REG3);
-+              core_reset = 0xffff - (1 << (lane + 8));
-+              mdio_wr(PHYMISC_REG3, val2 & core_reset);
-+      }
-+}
-+
-+void tx_restart(int lane)
-+{
-+      tx_core_assert(lane);
-+      tx_pll_assert(lane);
-+      tx_pll_de_assert(lane);
-+      usleep_range(1500, 1600);
-+      tx_core_de_assert(lane);
-+}
-+
-+void disable_lane(int lane)
-+{
-+      rx_reset_assert(lane);
-+      rx_powerdown_assert(lane);
-+      tx_core_assert(lane);
-+      lol_disable(lane);
-+}
-+
-+void toggle_reset(int lane)
-+{
-+      int reg, val, orig;
-+
-+      if (lane == ALL_LANES) {
-+              mdio_wr(PHYMISC_REG2, 0x8000);
-+              udelay(100);
-+              mdio_wr(PHYMISC_REG2, 0x0000);
-+      } else {
-+              reg = lane * 0x100 + PHYCTRL_REG8;
-+              val = (1 << 6);
-+              orig = mdio_rd(reg);
-+              mdio_wr(reg, orig + val);
-+              udelay(100);
-+              mdio_wr(reg, orig);
-+      }
-+}
-+
-+int az_complete_test(int lane)
-+{
-+      int success = 1, value;
-+
-+      if (lane == 0 || lane == ALL_LANES) {
-+              value = mdio_rd(PHYCTRL_REG5);
-+              success = success & bit_test(value, 2);
-+      }
-+      if (lane == 1 || lane == ALL_LANES) {
-+              value = mdio_rd(PHYCTRL_REG5 + 0x100);
-+              success = success & bit_test(value, 2);
-+      }
-+      if (lane == 2 || lane == ALL_LANES) {
-+              value = mdio_rd(PHYCTRL_REG5 + 0x200);
-+              success = success & bit_test(value, 2);
-+      }
-+      if (lane == 3 || lane == ALL_LANES) {
-+              value = mdio_rd(PHYCTRL_REG5 + 0x300);
-+              success = success & bit_test(value, 2);
-+      }
-+
-+      return success;
-+}
-+
-+void save_az_offsets(int lane)
-+{
-+      int i;
-+
-+#define AZ_OFFSET_LANE_UPDATE(reg, lane) \
-+      mdio_wr((reg) + (lane) * 0x100,  \
-+              (mdio_rd((reg) + (lane) * 0x100) >> 8))
-+
-+      if (lane == ALL_LANES) {
-+              for (i = 0; i < ALL_LANES; i++) {
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, i);
-+                      AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, i);
-+              }
-+      } else {
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 1, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 2, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG20 + 3, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 1, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 2, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG21 + 3, lane);
-+              AZ_OFFSET_LANE_UPDATE(PHYMISC_REG22, lane);
-+      }
-+
-+      mdio_wr(PHYCTRL_REG7, 0x0001);
-+}
-+
-+void save_vco_codes(int lane)
-+{
-+      int i;
-+
-+      if (lane == ALL_LANES) {
-+              for (i = 0; i < ALL_LANES; i++) {
-+                      vco_codes[i] = mdio_rd(PHYMISC_REG5 + i * 0x100);
-+                      mdio_wr(PHYMISC_REG5 + i * 0x100,
-+                              vco_codes[i] + RX_VCO_CODE_OFFSET);
-+              }
-+      } else {
-+              vco_codes[lane] = mdio_rd(PHYMISC_REG5 + lane * 0x100);
-+              mdio_wr(PHYMISC_REG5 + lane * 0x100,
-+                      vco_codes[lane] + RX_VCO_CODE_OFFSET);
-+      }
-+}
-+
-+int inphi_lane_recovery(int lane)
-+{
-+      int i, value, az_pass;
-+
-+      switch (lane) {
-+      case 0:
-+      case 1:
-+      case 2:
-+      case 3:
-+              rx_reset_assert(lane);
-+              mdelay(20);
-+              break;
-+      case ALL_LANES:
-+              mdio_wr(PHYMISC_REG2, 0x9C00);
-+              mdelay(20);
-+              do {
-+                      value = mdio_rd(PHYMISC_REG2);
-+                      udelay(10);
-+              } while (!bit_test(value, 4));
-+              break;
-+      default:
-+              dev_err(&inphi_phydev->mdio.dev,
-+                      "Incorrect usage of APIs in %s driver\n",
-+                      inphi_phydev->drv->name);
-+              break;
-+      }
-+
-+      if (lane == ALL_LANES) {
-+              for (i = 0; i < ALL_LANES; i++)
-+                      mdio_wr(PHYMISC_REG7 + i * 0x100, VCO_CODE);
-+      } else {
-+              mdio_wr(PHYMISC_REG7 + lane * 0x100, VCO_CODE);
-+      }
-+
-+      if (lane == ALL_LANES)
-+              for (i = 0; i < ALL_LANES; i++)
-+                      mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0418);
-+      else
-+              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0418);
-+
-+      mdio_wr(PHYCTRL_REG7,   0x0000);
-+
-+      rx_reset_de_assert(lane);
-+
-+      if (lane == ALL_LANES) {
-+              for (i = 0; i < ALL_LANES; i++) {
-+                      mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0410);
-+                      mdio_wr(PHYCTRL_REG5 + i * 0x100, 0x0412);
-+              }
-+      } else {
-+              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0410);
-+              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0412);
-+      }
-+
-+      for (i = 0; i < 64; i++) {
-+              mdelay(100);
-+              az_pass = az_complete_test(lane);
-+              if (az_pass) {
-+                      save_az_offsets(lane);
-+                      break;
-+              }
-+      }
-+
-+      if (!az_pass) {
-+              pr_info("in112525: AZ calibration fail @ lane=%d\n", lane);
-+              return -1;
-+      }
-+
-+      if (lane == ALL_LANES) {
-+              mdio_wr(PHYMISC_REG8, 0x0002);
-+              mdio_wr(PHYMISC_REG9, 0x2028);
-+              mdio_wr(PHYCTRL_REG6, 0x0010);
-+              usleep_range(1000, 1200);
-+              mdio_wr(PHYCTRL_REG6, 0x0110);
-+              mdelay(30);
-+              mdio_wr(PHYMISC_REG9, 0x3020);
-+      } else {
-+              mdio_wr(PHYMISC_REG4 + lane * 0x100, 0x0002);
-+              mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x2028);
-+              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0010);
-+              usleep_range(1000, 1200);
-+              mdio_wr(PHYCTRL_REG5 + lane * 0x100, 0x0110);
-+              mdelay(30);
-+              mdio_wr(PHYMISC_REG6 + lane * 0x100, 0x3020);
-+      }
-+
-+      if (lane == ALL_LANES) {
-+              mdio_wr(PHYMISC_REG2, 0x1C00);
-+              mdio_wr(PHYMISC_REG2, 0x0C00);
-+      } else {
-+              tx_restart(lane);
-+              mdelay(11);
-+      }
-+
-+      if (lane == ALL_LANES) {
-+              if (bit_test(mdio_rd(PHYMISC_REG2), 6) == 0)
-+                      return -1;
-+      } else {
-+              if (tx_pll_lock_test(lane) == 0)
-+                      return -1;
-+      }
-+
-+      save_vco_codes(lane);
-+
-+      if (lane == ALL_LANES) {
-+              mdio_wr(PHYMISC_REG2, 0x0400);
-+              mdio_wr(PHYMISC_REG2, 0x0000);
-+              value = mdio_rd(PHYCTRL_REG1);
-+              value = value & 0xffbf;
-+              mdio_wr(PHYCTRL_REG2, value);
-+      } else {
-+              tx_core_de_assert(lane);
-+      }
-+
-+      if (lane == ALL_LANES) {
-+              mdio_wr(PHYMISC_REG1, 0x8000);
-+              mdio_wr(PHYMISC_REG1, 0x0000);
-+      }
-+      mdio_rd(PHYMISC_REG1);
-+      mdio_rd(PHYMISC_REG1);
-+      usleep_range(1000, 1200);
-+      mdio_rd(PHYSTAT_REG1);
-+      mdio_rd(PHYSTAT_REG2);
-+
-+      return 0;
-+}
-+
-+static void mykmod_work_handler(struct work_struct *w)
-+{
-+      int all_lanes_lock, lane0_lock, lane1_lock, lane2_lock, lane3_lock;
-+
-+      lane0_lock = bit_test(mdio_rd(0x123), 15);
-+      lane1_lock = bit_test(mdio_rd(0x223), 15);
-+      lane2_lock = bit_test(mdio_rd(0x323), 15);
-+      lane3_lock = bit_test(mdio_rd(0x423), 15);
-+
-+      /* check if the chip had any successful lane lock from the previous
-+       * stage (e.g. u-boot)
-+       */
-+      all_lanes_lock = lane0_lock | lane1_lock | lane2_lock | lane3_lock;
-+
-+      if (!all_lanes_lock) {
-+              /* start fresh */
-+              inphi_lane_recovery(ALL_LANES);
-+      } else {
-+              if (!lane0_lock)
-+                      inphi_lane_recovery(0);
-+              if (!lane1_lock)
-+                      inphi_lane_recovery(1);
-+              if (!lane2_lock)
-+                      inphi_lane_recovery(2);
-+              if (!lane3_lock)
-+                      inphi_lane_recovery(3);
-+      }
-+
-+      queue_delayed_work(wq, &mykmod_work, onesec);
-+}
-+
-+int inphi_probe(struct phy_device *phydev)
-+{
-+      int phy_id = 0, id_lsb = 0, id_msb = 0;
-+
-+      /* setup the inphi_phydev ptr for mdio_rd/mdio_wr APIs */
-+      inphi_phydev = phydev;
-+
-+      /* Read device id from phy registers */
-+      id_lsb = mdio_rd(INPHI_S03_DEVICE_ID_MSB);
-+      if (id_lsb < 0)
-+              return -ENXIO;
-+
-+      phy_id = id_lsb << 16;
-+
-+      id_msb = mdio_rd(INPHI_S03_DEVICE_ID_LSB);
-+      if (id_msb < 0)
-+              return -ENXIO;
-+
-+      phy_id |= id_msb;
-+
-+      /* Make sure the device tree binding matched the driver with the
-+       * right device.
-+       */
-+      if (phy_id != phydev->drv->phy_id) {
-+              dev_err(&phydev->mdio.dev,
-+                      "Error matching phy with %s driver\n",
-+                      phydev->drv->name);
-+              return -ENODEV;
-+      }
-+
-+      /* update the local phydev pointer, used inside all APIs */
-+      inphi_phydev = phydev;
-+      onesec = msecs_to_jiffies(INPHI_POLL_DELAY);
-+
-+      wq = create_singlethread_workqueue("inphi_kmod");
-+      if (wq) {
-+              queue_delayed_work(wq, &mykmod_work, onesec);
-+      } else {
-+              dev_err(&phydev->mdio.dev,
-+                      "Error creating kernel workqueue for %s driver\n",
-+                      phydev->drv->name);
-+              return -ENOMEM;
-+      }
-+
-+      return 0;
-+}
-+
-+static struct phy_driver inphi_driver[] = {
-+{
-+      .phy_id         = PHY_ID_IN112525,
-+      .phy_id_mask    = 0x0ff0fff0,
-+      .name           = "Inphi 112525_S03",
-+      .features       = PHY_GBIT_FEATURES,
-+      .probe          = &inphi_probe,
-+},
-+};
-+
-+module_phy_driver(inphi_driver);
-+
-+static struct mdio_device_id __maybe_unused inphi_tbl[] = {
-+      { PHY_ID_IN112525, 0x0ff0fff0},
-+      {},
-+};
-+
-+MODULE_DEVICE_TABLE(mdio, inphi_tbl);
---- /dev/null
-+++ b/drivers/net/phy/mdio-mux-multiplexer.c
-@@ -0,0 +1,122 @@
-+// SPDX-License-Identifier: GPL-2.0+
-+/* MDIO bus multiplexer using kernel multiplexer subsystem
-+ *
-+ * Copyright 2019 NXP
-+ */
-+
-+#include <linux/platform_device.h>
-+#include <linux/mdio-mux.h>
-+#include <linux/module.h>
-+#include <linux/mux/consumer.h>
-+
-+struct mdio_mux_multiplexer_state {
-+      struct mux_control *muxc;
-+      bool do_deselect;
-+      void *mux_handle;
-+};
-+
-+/**
-+ * mdio_mux_multiplexer_switch_fn - This function is called by the mdio-mux
-+ *                                  layer when it thinks the mdio bus
-+ *                                  multiplexer needs to switch.
-+ * @current_child:  current value of the mux register.
-+ * @desired_child: value of the 'reg' property of the target child MDIO node.
-+ * @data: Private data used by this switch_fn passed to mdio_mux_init function
-+ *        via mdio_mux_init(.., .., .., .., data, ..).
-+ *
-+ * The first time this function is called, current_child == -1.
-+ * If current_child == desired_child, then the mux is already set to the
-+ * correct bus.
-+ */
-+static int mdio_mux_multiplexer_switch_fn(int current_child, int desired_child,
-+                                        void *data)
-+{
-+      struct platform_device *pdev;
-+      struct mdio_mux_multiplexer_state *s;
-+      int ret = 0;
-+
-+      pdev = (struct platform_device *)data;
-+      s = platform_get_drvdata(pdev);
-+
-+      if (!(current_child ^ desired_child))
-+              return 0;
-+
-+      if (s->do_deselect)
-+              ret = mux_control_deselect(s->muxc);
-+      if (ret) {
-+              dev_err(&pdev->dev, "mux_control_deselect failed in %s: %d\n",
-+                      __func__, ret);
-+              return ret;
-+      }
-+
-+      ret =  mux_control_select(s->muxc, desired_child);
-+      if (!ret) {
-+              dev_dbg(&pdev->dev, "%s %d -> %d\n", __func__, current_child,
-+                      desired_child);
-+              s->do_deselect = true;
-+      } else {
-+              s->do_deselect = false;
-+      }
-+
-+      return ret;
-+}
-+
-+static int mdio_mux_multiplexer_probe(struct platform_device *pdev)
-+{
-+      struct device *dev = &pdev->dev;
-+      struct mdio_mux_multiplexer_state *s;
-+      int ret = 0;
-+
-+      s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
-+      if (!s)
-+              return -ENOMEM;
-+
-+      s->muxc = devm_mux_control_get(dev, NULL);
-+      if (IS_ERR(s->muxc)) {
-+              ret = PTR_ERR(s->muxc);
-+              if (ret != -EPROBE_DEFER)
-+                      dev_err(&pdev->dev, "Failed to get mux: %d\n", ret);
-+              return ret;
-+      }
-+
-+      platform_set_drvdata(pdev, s);
-+
-+      ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node,
-+                          mdio_mux_multiplexer_switch_fn, &s->mux_handle,
-+                          pdev, NULL);
-+
-+      return ret;
-+}
-+
-+static int mdio_mux_multiplexer_remove(struct platform_device *pdev)
-+{
-+      struct mdio_mux_multiplexer_state *s = platform_get_drvdata(pdev);
-+
-+      mdio_mux_uninit(s->mux_handle);
-+
-+      if (s->do_deselect)
-+              mux_control_deselect(s->muxc);
-+
-+      return 0;
-+}
-+
-+static const struct of_device_id mdio_mux_multiplexer_match[] = {
-+      { .compatible = "mdio-mux-multiplexer", },
-+      {},
-+};
-+MODULE_DEVICE_TABLE(of, mdio_mux_multiplexer_match);
-+
-+static struct platform_driver mdio_mux_multiplexer_driver = {
-+      .driver = {
-+              .name           = "mdio-mux-multiplexer",
-+              .of_match_table = mdio_mux_multiplexer_match,
-+      },
-+      .probe          = mdio_mux_multiplexer_probe,
-+      .remove         = mdio_mux_multiplexer_remove,
-+};
-+
-+module_platform_driver(mdio_mux_multiplexer_driver);
-+
-+MODULE_DESCRIPTION("MDIO bus multiplexer using kernel multiplexer subsystem");
-+MODULE_AUTHOR("Pankaj Bansal <pankaj.bansal@nxp.com>");
-+MODULE_LICENSE("GPL");
---- a/drivers/net/phy/swphy.c
-+++ b/drivers/net/phy/swphy.c
-@@ -77,6 +77,7 @@ static const struct swmii_regs duplex[]
- static int swphy_decode_speed(int speed)
- {
-       switch (speed) {
-+      case 10000:
-       case 1000:
-               return SWMII_SPEED_1000;
-       case 100:
---- a/include/linux/phy.h
-+++ b/include/linux/phy.h
-@@ -87,6 +87,7 @@ typedef enum {
-       PHY_INTERFACE_MODE_XAUI,
-       /* 10GBASE-KR, XFI, SFI - single lane 10G Serdes */
-       PHY_INTERFACE_MODE_10GKR,
-+      PHY_INTERFACE_MODE_2500SGMII,
-       PHY_INTERFACE_MODE_MAX,
- } phy_interface_t;
-@@ -159,6 +160,8 @@ static inline const char *phy_modes(phy_
-               return "xaui";
-       case PHY_INTERFACE_MODE_10GKR:
-               return "10gbase-kr";
-+      case PHY_INTERFACE_MODE_2500SGMII:
-+              return "sgmii-2500";
-       default:
-               return "unknown";
-       }