Added marvel m88e1512 1G PHY support in amd axgbe driver

Signed-off-by: Ashok Kumar Natarajan <[email protected]>
---
 .mailmap                           |   1 +
 drivers/net/axgbe/axgbe_ethdev.h   |   4 +
 drivers/net/axgbe/axgbe_mdio.c     |   4 +-
 drivers/net/axgbe/axgbe_phy.h      |  32 +++
 drivers/net/axgbe/axgbe_phy_impl.c | 309 ++++++++++++++++++++++++++++-
 5 files changed, 343 insertions(+), 7 deletions(-)

diff --git a/.mailmap b/.mailmap
index 8bbfcc1703..6f951bcd92 100644
--- a/.mailmap
+++ b/.mailmap
@@ -165,6 +165,7 @@ Ashish Paul <[email protected]>
 Ashish Sadanandan <[email protected]>
 Ashish Shah <[email protected]>
 Ashok Kaladi <[email protected]>
+Ashok Kumar Natarajan <[email protected]>
 Ashwin Sekhar T K <[email protected]> <[email protected]>
 Asim Jamshed <[email protected]>
 Atul Patel <[email protected]>
diff --git a/drivers/net/axgbe/axgbe_ethdev.h b/drivers/net/axgbe/axgbe_ethdev.h
index b94a7f3562..3a9dc81691 100644
--- a/drivers/net/axgbe/axgbe_ethdev.h
+++ b/drivers/net/axgbe/axgbe_ethdev.h
@@ -276,6 +276,7 @@ struct axgbe_phy {
        int pause_autoneg;
        int tx_pause;
        int rx_pause;
+       int id;
 };
 
 enum axgbe_i2c_cmd {
@@ -398,6 +399,9 @@ struct axgbe_phy_impl_if {
        /* Pre/Post KR training enablement support */
        void (*kr_training_pre)(struct axgbe_port *);
        void (*kr_training_post)(struct axgbe_port *);
+
+       int (*read)(struct axgbe_port *port, int addr, int reg);
+       int (*write)(struct axgbe_port *port, int addr, int reg, u16 val);
 };
 
 struct axgbe_phy_if {
diff --git a/drivers/net/axgbe/axgbe_mdio.c b/drivers/net/axgbe/axgbe_mdio.c
index 952a0add62..a37cd8b80d 100644
--- a/drivers/net/axgbe/axgbe_mdio.c
+++ b/drivers/net/axgbe/axgbe_mdio.c
@@ -155,8 +155,8 @@ static void axgbe_sgmii_10_mode(struct axgbe_port *pdata)
 static void axgbe_sgmii_100_mode(struct axgbe_port *pdata)
 {
 
-       /* Set MAC to 1G speed */
-       pdata->hw_if.set_speed(pdata, SPEED_1000);
+       /* Set MAC to 100M speed */
+       pdata->hw_if.set_speed(pdata, SPEED_100);
 
        /* Call PHY implementation support to complete rate change */
        pdata->phy_if.phy_impl.set_mode(pdata, AXGBE_MODE_SGMII_100);
diff --git a/drivers/net/axgbe/axgbe_phy.h b/drivers/net/axgbe/axgbe_phy.h
index eee3afc370..ef02488adf 100644
--- a/drivers/net/axgbe/axgbe_phy.h
+++ b/drivers/net/axgbe/axgbe_phy.h
@@ -63,6 +63,29 @@
 #define BMCR_RESET             0x8000  /* Reset to default state      */
 #define BMCR_SPEED10           0x0000  /* Select 10Mbps               */
 
+/* Advertisement control register. */
+#define ADVERTISE_SLCT          0x001f  /* Selector bits               */
+#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */
+#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */
+#define ADVERTISE_1000XFULL     0x0020  /* Try for 1000BASE-X full-duplex */
+#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */
+#define ADVERTISE_1000XHALF     0x0040  /* Try for 1000BASE-X half-duplex */
+#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */
+#define ADVERTISE_1000XPAUSE    0x0080  /* Try for 1000BASE-X pause    */
+#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */
+#define ADVERTISE_1000XPSE_ASYM 0x0100  /* Try for 1000BASE-X asym pause */
+#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */
+#define ADVERTISE_PAUSE_CAP     0x0400  /* Try for pause               */
+#define ADVERTISE_PAUSE_ASYM    0x0800  /* Try for asymmetric pause     */
+#define ADVERTISE_RESV          0x1000  /* Unused...                   */
+#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */
+#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */
+#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */
+
+#define ADVERTISE_FULL          (ADVERTISE_100FULL | ADVERTISE_10FULL | \
+               ADVERTISE_CSMA)
+#define ADVERTISE_ALL           (ADVERTISE_10HALF | ADVERTISE_10FULL | \
+               ADVERTISE_100HALF | ADVERTISE_100FULL)
 
 /* MDIO Manageable Devices (MMDs). */
 #define MDIO_MMD_PMAPMD                1       /* Physical Medium Attachment
@@ -114,6 +137,15 @@
 #define MDIO_AN_10GBT_CTRL     32      /* 10GBASE-T auto-negotiation control */
 #define MDIO_AN_10GBT_STAT     33      /* 10GBASE-T auto-negotiation status */
 
+#define AXGBE_M88E1512_PAGE_ADDR       0x0016
+#define AXGBE_M88E1512_CFG_REG_1       0x0010
+#define AXGBE_M88E1512_CFG_REG_2       0x0011
+#define AXGBE_M88E1512_CFG_REG_3       0x0007
+#define AXGBE_M88E1512_MODE            0x0014
+
+#define AXGBE_M88E1512_SCR             0x10
+
+
 /* Control register 1. */
 /* Enable extended speed selection */
 #define MDIO_CTRL1_SPEEDSELEXT         (BMCR_SPEED1000 | BMCR_SPEED100)
diff --git a/drivers/net/axgbe/axgbe_phy_impl.c 
b/drivers/net/axgbe/axgbe_phy_impl.c
index 9249e11335..96773dd722 100644
--- a/drivers/net/axgbe/axgbe_phy_impl.c
+++ b/drivers/net/axgbe/axgbe_phy_impl.c
@@ -37,6 +37,8 @@
 #define AXGBE_CDR_DELAY_INC            10000
 #define AXGBE_CDR_DELAY_MAX            100000
 
+#define M88E1512_E_PHY_ID              0x01410DD0
+
 enum axgbe_port_mode {
        AXGBE_PORT_MODE_RSVD = 0,
        AXGBE_PORT_MODE_BACKPLANE,
@@ -250,7 +252,11 @@ static enum axgbe_an_mode axgbe_phy_an_mode(struct 
axgbe_port *pdata);
 static void axgbe_phy_perform_ratechange(struct axgbe_port *pdata,
                enum axgbe_mb_cmd cmd, enum axgbe_mb_subcmd sub_cmd);
 static void axgbe_phy_rrc(struct axgbe_port *pdata);
+static int axgbe_get_ext_phy_link_status(struct axgbe_port *pdata);
 
+static int axgbe_phy_get_comm_ownership(struct axgbe_port *pdata);
+static void axgbe_phy_put_comm_ownership(struct axgbe_port *pdata);
+static int axgbe_m88e1512_config_aneg(struct axgbe_port *pdata);
 
 static int axgbe_phy_i2c_xfer(struct axgbe_port *pdata,
                              struct axgbe_i2c_op *i2c_op)
@@ -258,6 +264,29 @@ static int axgbe_phy_i2c_xfer(struct axgbe_port *pdata,
        return pdata->i2c_if.i2c_xfer(pdata, i2c_op);
 }
 
+static int axgbe_phy_mii_read_c22(struct axgbe_port *pdata, int addr, int reg)
+{
+       int ret, regval;
+       ret = axgbe_phy_get_comm_ownership(pdata);
+       if (ret)
+               return -1;
+       regval = pdata->hw_if.read_ext_mii_regs_c22(pdata, addr, reg);
+       axgbe_phy_put_comm_ownership(pdata);
+       return regval;
+}
+
+static int axgbe_phy_mii_write_c22(struct axgbe_port *pdata, int addr,
+               int reg, u16 val)
+{
+       int ret, regval;
+       ret = axgbe_phy_get_comm_ownership(pdata);
+       if (ret)
+               return -1;
+       regval = pdata->hw_if.write_ext_mii_regs_c22(pdata, addr, reg, val);
+       axgbe_phy_put_comm_ownership(pdata);
+       return regval;
+}
+
 static int axgbe_phy_redrv_write(struct axgbe_port *pdata, unsigned int reg,
                                 unsigned int val)
 {
@@ -1090,12 +1119,17 @@ static unsigned int axgbe_phy_an_advertising(struct 
axgbe_port *pdata)
        return advertising;
 }
 
-static int axgbe_phy_an_config(struct axgbe_port *pdata __rte_unused)
+static int axgbe_phy_an_config(struct axgbe_port *pdata)
 {
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+
+       if (phy_data->port_mode != AXGBE_PORT_MODE_1000BASE_T)
+               return 0;
+
+       if (pdata->phy.id == M88E1512_E_PHY_ID)
+               axgbe_m88e1512_config_aneg(pdata);
+
        return 0;
-       /* Dummy API since there is no case to support
-        * external phy devices registered through kernel APIs
-        */
 }
 
 static enum axgbe_an_mode axgbe_phy_an_sfp_mode(struct axgbe_phy_data 
*phy_data)
@@ -1207,6 +1241,7 @@ static void axgbe_set_rx_adap_mode(struct axgbe_port 
*pdata,
 {
        if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) {
                pdata->rx_adapt_retries = 0;
+               pdata->mode_set = false;
                return;
        }
 
@@ -1497,6 +1532,18 @@ static void axgbe_phy_sgmii_1000_mode(struct axgbe_port 
*pdata)
        phy_data->cur_mode = AXGBE_MODE_SGMII_1000;
 }
 
+static void axgbe_phy_sgmii_100_mode(struct axgbe_port *pdata)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+
+       axgbe_phy_set_redrv_mode(pdata);
+
+       /* 100M/SGMII */
+       axgbe_phy_perform_ratechange(pdata, AXGBE_MB_CMD_SET_1G, 
AXGBE_MB_SUBCMD_100MBITS);
+
+       phy_data->cur_mode = AXGBE_MODE_SGMII_100;
+}
+
 static void axgbe_phy_sgmii_10_mode(struct axgbe_port *pdata)
 {
        struct axgbe_phy_data *phy_data = pdata->phy_data;
@@ -1694,6 +1741,9 @@ static void axgbe_phy_set_mode(struct axgbe_port *pdata, 
enum axgbe_mode mode)
        case AXGBE_MODE_SGMII_1000:
                axgbe_phy_sgmii_1000_mode(pdata);
                break;
+       case AXGBE_MODE_SGMII_100:
+               axgbe_phy_sgmii_100_mode(pdata);
+               break;
        case AXGBE_MODE_SGMII_10:
                axgbe_phy_sgmii_10_mode(pdata);
                break;
@@ -1863,6 +1913,17 @@ static int axgbe_phy_link_status(struct axgbe_port 
*pdata, int *an_restart)
                }
        }
 
+       if (phy_data->port_mode == AXGBE_PORT_MODE_1000BASE_T) {
+               if (pdata->phy.id == M88E1512_E_PHY_ID) {
+                       if (axgbe_get_ext_phy_link_status(pdata) == 1) {
+                               PMD_DRV_LOG_LINE(DEBUG, "M88E1512 PHY link is 
up");
+                       } else {
+                               PMD_DRV_LOG_LINE(DEBUG, "M88E1512 PHY link is 
not up");
+                               goto out;
+                       }
+               }
+       }
+
        /* Link status is latched low, so read once to clear
         * and then read again to get current state
         */
@@ -1905,7 +1966,8 @@ static int axgbe_phy_link_status(struct axgbe_port 
*pdata, int *an_restart)
                phy_data->rrc_count = 0;
                axgbe_phy_rrc(pdata);
        }
-
+out:
+       pdata->rx_adapt_done = false;
        return 0;
 }
 
@@ -2263,6 +2325,226 @@ static int axgbe_phy_reset(struct axgbe_port *pdata)
        return 0;
 }
 
+static int axgbe_m88e5112_set_page(struct axgbe_port *pdata, int page)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int mdio_addr = phy_data->mdio_addr;
+       return pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                       AXGBE_M88E1512_PAGE_ADDR, page);
+}
+
+static int axgbe_get_phy_id(struct axgbe_port *pdata)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int mdio_addr = phy_data->mdio_addr;
+       int phy_id, ret_val;
+       ret_val = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_PHYSID1);
+
+       phy_id = ret_val << 16;
+
+       ret_val = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_PHYSID2);
+       phy_id |= ret_val & 0xfff0;
+
+       return phy_id;
+}
+
+static int axgbe_m88e1512_soft_reset(struct axgbe_port *pdata)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int mdio_addr = phy_data->mdio_addr;
+       int bmcr;
+       int ret;
+
+       bmcr = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_BMCR);
+       if (bmcr == -1)
+               goto out;
+       bmcr |= BMCR_RESET;
+       ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr, MII_BMCR, bmcr);
+       if (ret)
+               return ret;
+
+       rte_delay_us_sleep(1);
+out:
+       return ret;
+}
+
+static int axgbe_m88e1512_config_aneg(struct axgbe_port *pdata)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int mdio_addr = phy_data->mdio_addr;
+       int an_advert, bmcr;
+       int ret;
+
+       an_advert = ADVERTISE_10FULL |
+               ADVERTISE_100FULL |
+               ADVERTISE_PAUSE_CAP |
+               ADVERTISE_PAUSE_ASYM;
+
+       ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                       MII_ADVERTISE, an_advert);
+       if (ret)
+               return ret;
+
+       bmcr = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_BMCR);
+       if (bmcr < 0)
+               return bmcr;
+
+       bmcr &= ~(MDIO_CTRL1_SPEEDSELEXT);
+       switch (phy_data->cur_mode) {
+       case AXGBE_MODE_SGMII_1000:
+               bmcr |= BMCR_SPEED1000;
+               break;
+       case AXGBE_MODE_SGMII_100:
+               bmcr |= BMCR_SPEED100;
+               break;
+       default:
+               break;
+       }
+       if (pdata->phy.autoneg == AUTONEG_ENABLE)
+               bmcr |=  BMCR_ANENABLE | BMCR_ANRESTART;
+
+       ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                       MII_BMCR, bmcr);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static const struct {
+       u16 reg17, reg16;
+} errata_vals[] = {
+       { 0x214b, 0x2144 },
+       { 0x0c28, 0x2146 },
+       { 0xb233, 0x214d },
+       { 0xcc0c, 0x2159 },
+};
+
+static int axgbe_m88e1512_init(struct axgbe_port *pdata)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int mdio_addr = phy_data->mdio_addr;
+       int ret;
+       unsigned int i;
+
+       PMD_DRV_LOG_LINE(DEBUG, "Initialize M88E1512 phy");
+
+       /* Switch to PHY page 0xFF */
+       ret = axgbe_m88e5112_set_page(pdata, 0xff);
+       if (ret)
+               return ret;
+       /* Configure M88E1512 errata registers */
+       for (i = 0; i < ARRAY_SIZE(errata_vals); i++) {
+               ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                               AXGBE_M88E1512_CFG_REG_2,
+                               errata_vals[i].reg17);
+               if (ret)
+                       return ret;
+
+               ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                               AXGBE_M88E1512_CFG_REG_1,
+                               errata_vals[i].reg16);
+               if (ret)
+                       return ret;
+       }
+
+       /* Switch to PHY page 0xFB */
+       ret = axgbe_m88e5112_set_page(pdata, 0xfb);
+       if (ret)
+               return ret;
+
+       ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                       AXGBE_M88E1512_CFG_REG_3, 0xC00D);
+       if (ret)
+               return ret;
+
+       /* Switch to PHY page 0 */
+       ret = axgbe_m88e5112_set_page(pdata, 0);
+       if (ret)
+               return ret;
+
+       /* SGMII-to-Copper mode initialization */
+
+       /* Switch to PHY page 0x12 */
+       ret = axgbe_m88e5112_set_page(pdata, 0x12);
+       if (ret)
+               return ret;
+
+       ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                       AXGBE_M88E1512_MODE, 0x8001);
+       if (ret)
+               return ret;
+
+       /* Switch to PHY page 0 */
+       ret = axgbe_m88e5112_set_page(pdata, 0);
+       if (ret)
+               return ret;
+
+       ret = axgbe_m88e1512_soft_reset(pdata);
+       if (ret)
+               return ret;
+
+       rte_delay_ms(1000);
+
+
+       /* Switch to PHY page 3 */
+       ret = axgbe_m88e5112_set_page(pdata, 3);
+       if (ret)
+               return ret;
+
+       /* enable downshift */
+       ret = pdata->phy_if.phy_impl.write(pdata, mdio_addr,
+                       AXGBE_M88E1512_SCR, 0x1177);
+       if (ret)
+               return ret;
+
+
+       /* Switch to PHY page 0 */
+       ret = axgbe_m88e5112_set_page(pdata, 0);
+       if (ret)
+               return ret;
+
+       ret = axgbe_m88e1512_soft_reset(pdata);
+       if (ret)
+               return ret;
+
+       rte_delay_ms(1000);
+
+       PMD_DRV_LOG_LINE(DEBUG, "M88E1512 phy init done");
+       return 0;
+}
+
+
+static int axgbe_get_ext_phy_link_status(struct axgbe_port *pdata)
+{
+       struct axgbe_phy_data *phy_data = pdata->phy_data;
+       unsigned int mdio_addr = phy_data->mdio_addr;
+       int status = 0, bmcr;
+
+       bmcr = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_BMCR);
+       if (bmcr < 0)
+               return bmcr;
+
+       /* Autoneg is being started, therefore disregard BMSR value and
+        * report link as down.
+        */
+       if (bmcr & BMCR_ANRESTART)
+               return 0;
+
+       status = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_BMSR);
+       if (status < 0)
+               return status;
+       else if (status & BMSR_LSTATUS)
+               goto done;
+
+       /* Read link and autonegotiation status */
+       status = pdata->phy_if.phy_impl.read(pdata, mdio_addr, MII_BMSR);
+       if (status < 0)
+               return status;
+done:
+       return (status & BMSR_LSTATUS) ? 1 : 0;
+}
+
 static int axgbe_phy_init(struct axgbe_port *pdata)
 {
        struct axgbe_phy_data *phy_data;
@@ -2292,6 +2574,12 @@ static int axgbe_phy_init(struct axgbe_port *pdata)
        phy_data->conn_type = XP_GET_BITS(pdata->pp0, XP_PROP_0, CONN_TYPE);
        phy_data->mdio_addr = XP_GET_BITS(pdata->pp0, XP_PROP_0, MDIO_ADDR);
 
+       PMD_DRV_LOG_LINE(DEBUG, "port mode  : %d", phy_data->port_mode);
+       PMD_DRV_LOG_LINE(DEBUG, "port id    : %d", phy_data->port_id);
+       PMD_DRV_LOG_LINE(DEBUG, "port speed : %d", phy_data->port_speeds);
+       PMD_DRV_LOG_LINE(DEBUG, "conn type  : %d", phy_data->conn_type);
+       PMD_DRV_LOG_LINE(DEBUG, "mdio addr  : %d", phy_data->mdio_addr);
+
        phy_data->redrv = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_PRESENT);
        phy_data->redrv_if = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_IF);
        phy_data->redrv_addr = XP_GET_BITS(pdata->pp4, XP_PROP_4, REDRV_ADDR);
@@ -2516,8 +2804,16 @@ static int axgbe_phy_init(struct axgbe_port *pdata)
        }
 
        phy_data->phy_cdr_delay = AXGBE_CDR_DELAY_INIT;
+
+       pdata->phy.id = axgbe_get_phy_id(pdata);
+       PMD_DRV_LOG_LINE(DEBUG, "PHY ID = 0x%x", pdata->phy.id);
+
+       if (pdata->phy.id == M88E1512_E_PHY_ID)
+               axgbe_m88e1512_init(pdata);
+
        return 0;
 }
+
 void axgbe_init_function_ptrs_phy_v2(struct axgbe_phy_if *phy_if)
 {
        struct axgbe_phy_impl_if *phy_impl = &phy_if->phy_impl;
@@ -2542,4 +2838,7 @@ void axgbe_init_function_ptrs_phy_v2(struct axgbe_phy_if 
*phy_if)
 
        phy_impl->kr_training_pre       = axgbe_phy_kr_training_pre;
        phy_impl->kr_training_post      = axgbe_phy_kr_training_post;
+
+       phy_impl->read                  = axgbe_phy_mii_read_c22;
+       phy_impl->write                 = axgbe_phy_mii_write_c22;
 }
-- 
2.34.1

Reply via email to