arm64: zynqmp: Point zcu216 defconfig to correct dts file
[oweals/u-boot.git] / drivers / net / ag7xxx.c
index 346f138caf85c49802ce9296d2176388660e51dc..804d5c20b6463d8c3e627511b006e5d7072c8013 100644 (file)
@@ -1,12 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Atheros AR71xx / AR9xxx GMAC driver
  *
  * Copyright (C) 2016 Marek Vasut <marex@denx.de>
- *
- * SPDX-License-Identifier:    GPL-2.0+
+ * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
  */
 
 #include <common.h>
+#include <cpu_func.h>
 #include <dm.h>
 #include <errno.h>
 #include <miiphy.h>
@@ -24,8 +25,11 @@ DECLARE_GLOBAL_DATA_PTR;
 enum ag7xxx_model {
        AG7XXX_MODEL_AG933X,
        AG7XXX_MODEL_AG934X,
+       AG7XXX_MODEL_AG953X,
+       AG7XXX_MODEL_AG956X
 };
 
+/* MAC Configuration 1 */
 #define AG7XXX_ETH_CFG1                                0x00
 #define AG7XXX_ETH_CFG1_SOFT_RST               BIT(31)
 #define AG7XXX_ETH_CFG1_RX_RST                 BIT(19)
@@ -34,6 +38,7 @@ enum ag7xxx_model {
 #define AG7XXX_ETH_CFG1_RX_EN                  BIT(2)
 #define AG7XXX_ETH_CFG1_TX_EN                  BIT(0)
 
+/* MAC Configuration 2 */
 #define AG7XXX_ETH_CFG2                                0x04
 #define AG7XXX_ETH_CFG2_IF_1000                        BIT(9)
 #define AG7XXX_ETH_CFG2_IF_10_100              BIT(8)
@@ -43,26 +48,34 @@ enum ag7xxx_model {
 #define AG7XXX_ETH_CFG2_PAD_CRC_EN             BIT(2)
 #define AG7XXX_ETH_CFG2_FDX                    BIT(0)
 
+/* MII Configuration */
 #define AG7XXX_ETH_MII_MGMT_CFG                        0x20
 #define AG7XXX_ETH_MII_MGMT_CFG_RESET          BIT(31)
 
+/* MII Command */
 #define AG7XXX_ETH_MII_MGMT_CMD                        0x24
 #define AG7XXX_ETH_MII_MGMT_CMD_READ           0x1
 
+/* MII Address */
 #define AG7XXX_ETH_MII_MGMT_ADDRESS            0x28
 #define AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT      8
 
+/* MII Control */
 #define AG7XXX_ETH_MII_MGMT_CTRL               0x2c
 
+/* MII Status */
 #define AG7XXX_ETH_MII_MGMT_STATUS             0x30
 
+/* MII Indicators */
 #define AG7XXX_ETH_MII_MGMT_IND                        0x34
 #define AG7XXX_ETH_MII_MGMT_IND_INVALID                BIT(2)
 #define AG7XXX_ETH_MII_MGMT_IND_BUSY           BIT(0)
 
+/* STA Address 1 & 2 */
 #define AG7XXX_ETH_ADDR1                       0x40
 #define AG7XXX_ETH_ADDR2                       0x44
 
+/* ETH Configuration 0 - 5 */
 #define AG7XXX_ETH_FIFO_CFG_0                  0x48
 #define AG7XXX_ETH_FIFO_CFG_1                  0x4c
 #define AG7XXX_ETH_FIFO_CFG_2                  0x50
@@ -70,22 +83,49 @@ enum ag7xxx_model {
 #define AG7XXX_ETH_FIFO_CFG_4                  0x58
 #define AG7XXX_ETH_FIFO_CFG_5                  0x5c
 
+/* DMA Transfer Control for Queue 0 */
 #define AG7XXX_ETH_DMA_TX_CTRL                 0x180
 #define AG7XXX_ETH_DMA_TX_CTRL_TXE             BIT(0)
 
+/* Descriptor Address for Queue 0 Tx */
 #define AG7XXX_ETH_DMA_TX_DESC                 0x184
 
+/* DMA Tx Status */
 #define AG7XXX_ETH_DMA_TX_STATUS               0x188
 
+/* Rx Control */
 #define AG7XXX_ETH_DMA_RX_CTRL                 0x18c
 #define AG7XXX_ETH_DMA_RX_CTRL_RXE             BIT(0)
 
+/* Pointer to Rx Descriptor */
 #define AG7XXX_ETH_DMA_RX_DESC                 0x190
 
+/* Rx Status */
 #define AG7XXX_ETH_DMA_RX_STATUS               0x194
 
+/* Custom register at 0x1805002C */
+#define AG7XXX_ETH_XMII                        0x2C
+#define AG7XXX_ETH_XMII_TX_INVERT              BIT(31)
+#define AG7XXX_ETH_XMII_RX_DELAY_LSB           28
+#define AG7XXX_ETH_XMII_RX_DELAY_MASK          0x30000000
+#define AG7XXX_ETH_XMII_RX_DELAY_SET(x) \
+       (((x) << AG7XXX_ETH_XMII_RX_DELAY_LSB) & AG7XXX_ETH_XMII_RX_DELAY_MASK)
+#define AG7XXX_ETH_XMII_TX_DELAY_LSB           26
+#define AG7XXX_ETH_XMII_TX_DELAY_MASK          0x0c000000
+#define AG7XXX_ETH_XMII_TX_DELAY_SET(x) \
+       (((x) << AG7XXX_ETH_XMII_TX_DELAY_LSB) & AG7XXX_ETH_XMII_TX_DELAY_MASK)
+#define AG7XXX_ETH_XMII_GIGE           BIT(25)
+
 /* Custom register at 0x18070000 */
 #define AG7XXX_GMAC_ETH_CFG                    0x00
+#define AG7XXX_ETH_CFG_RXDV_DELAY_LSB          16
+#define AG7XXX_ETH_CFG_RXDV_DELAY_MASK         0x00030000
+#define AG7XXX_ETH_CFG_RXDV_DELAY_SET(x) \
+       (((x) << AG7XXX_ETH_CFG_RXDV_DELAY_LSB) & AG7XXX_ETH_CFG_RXDV_DELAY_MASK)
+#define AG7XXX_ETH_CFG_RXD_DELAY_LSB           14
+#define AG7XXX_ETH_CFG_RXD_DELAY_MASK          0x0000c000
+#define AG7XXX_ETH_CFG_RXD_DELAY_SET(x)        \
+       (((x) << AG7XXX_ETH_CFG_RXD_DELAY_LSB) & AG7XXX_ETH_CFG_RXD_DELAY_MASK)
 #define AG7XXX_ETH_CFG_SW_PHY_ADDR_SWAP                BIT(8)
 #define AG7XXX_ETH_CFG_SW_PHY_SWAP             BIT(7)
 #define AG7XXX_ETH_CFG_SW_ONLY_MODE            BIT(6)
@@ -148,8 +188,8 @@ static int ag7xxx_switch_read(struct mii_dev *bus, int addr, int reg, u16 *val)
        writel(AG7XXX_ETH_MII_MGMT_CMD_READ,
               regs + AG7XXX_ETH_MII_MGMT_CMD);
 
-       ret = wait_for_bit("ag7xxx", regs + AG7XXX_ETH_MII_MGMT_IND,
-                          AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
+       ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND,
+                               AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
        if (ret)
                return ret;
 
@@ -169,8 +209,8 @@ static int ag7xxx_switch_write(struct mii_dev *bus, int addr, int reg, u16 val)
               regs + AG7XXX_ETH_MII_MGMT_ADDRESS);
        writel(val, regs + AG7XXX_ETH_MII_MGMT_CTRL);
 
-       ret = wait_for_bit("ag7xxx", regs + AG7XXX_ETH_MII_MGMT_IND,
-                          AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
+       ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND,
+                               AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
 
        return ret;
 }
@@ -182,24 +222,33 @@ static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val)
        u32 reg_addr;
        u32 phy_temp;
        u32 reg_temp;
+       u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
        u16 rv = 0;
        int ret;
 
-       if (priv->model == AG7XXX_MODEL_AG933X) {
+       if (priv->model == AG7XXX_MODEL_AG933X ||
+           priv->model == AG7XXX_MODEL_AG953X) {
                phy_addr = 0x1f;
                reg_addr = 0x10;
-       } else if (priv->model == AG7XXX_MODEL_AG934X) {
+       } else if (priv->model == AG7XXX_MODEL_AG934X ||
+                  priv->model == AG7XXX_MODEL_AG956X) {
                phy_addr = 0x18;
                reg_addr = 0x00;
        } else
                return -EINVAL;
 
-       ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
+       if (priv->model == AG7XXX_MODEL_AG956X)
+               ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
+       else
+               ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
        if (ret)
                return ret;
 
        phy_temp = ((reg >> 6) & 0x7) | 0x10;
-       reg_temp = (reg >> 1) & 0x1e;
+       if (priv->model == AG7XXX_MODEL_AG956X)
+               reg_temp = reg_temp_w & 0x1f;
+       else
+               reg_temp = (reg >> 1) & 0x1e;
        *val = 0;
 
        ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 0, &rv);
@@ -207,7 +256,13 @@ static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val)
                return ret;
        *val |= rv;
 
-       ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 1, &rv);
+       if (priv->model == AG7XXX_MODEL_AG956X) {
+               phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
+               reg_temp = (reg_temp_w + 1) & 0x1f;
+               ret = ag7xxx_switch_read(bus, phy_temp, reg_temp, &rv);
+       } else {
+               ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 1, &rv);
+       }
        if (ret < 0)
                return ret;
        *val |= (rv << 16);
@@ -222,23 +277,34 @@ static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
        u32 reg_addr;
        u32 phy_temp;
        u32 reg_temp;
+       u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
        int ret;
 
-       if (priv->model == AG7XXX_MODEL_AG933X) {
+       if (priv->model == AG7XXX_MODEL_AG933X ||
+           priv->model == AG7XXX_MODEL_AG953X) {
                phy_addr = 0x1f;
                reg_addr = 0x10;
-       } else if (priv->model == AG7XXX_MODEL_AG934X) {
+       } else if (priv->model == AG7XXX_MODEL_AG934X ||
+                  priv->model == AG7XXX_MODEL_AG956X) {
                phy_addr = 0x18;
                reg_addr = 0x00;
        } else
                return -EINVAL;
 
-       ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
+       if (priv->model == AG7XXX_MODEL_AG956X)
+               ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
+       else
+               ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
        if (ret)
                return ret;
 
-       phy_temp = ((reg >> 6) & 0x7) | 0x10;
-       reg_temp = (reg >> 1) & 0x1e;
+       if (priv->model == AG7XXX_MODEL_AG956X) {
+               reg_temp = (reg_temp_w + 1) & 0x1f;
+               phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
+       } else {
+               phy_temp = ((reg >> 6) & 0x7) | 0x10;
+               reg_temp = (reg >> 1) & 0x1e;
+       }
 
        /*
         * The switch on AR933x has some special register behavior, which
@@ -257,10 +323,18 @@ static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
                if (ret < 0)
                        return ret;
        } else {
-               ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
+               if (priv->model == AG7XXX_MODEL_AG956X)
+                       ret = ag7xxx_switch_write(bus, phy_temp, reg_temp, val >> 16);
+               else
+                       ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
                if (ret < 0)
                        return ret;
 
+               if (priv->model == AG7XXX_MODEL_AG956X) {
+                       phy_temp = ((reg_temp_w >> 5) & 0x7) | 0x10;
+                       reg_temp = reg_temp_w & 0x1f;
+               }
+
                ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 0, val & 0xffff);
                if (ret < 0)
                        return ret;
@@ -269,18 +343,33 @@ static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
        return 0;
 }
 
-static u16 ag7xxx_mdio_rw(struct mii_dev *bus, int addr, int reg, u32 val)
+static int ag7xxx_mdio_rw(struct mii_dev *bus, int addr, int reg, u32 val)
 {
        u32 data;
+       unsigned long start;
+       int ret;
+       /* No idea if this is long enough or too long */
+       int timeout_ms = 1000;
 
        /* Dummy read followed by PHY read/write command. */
-       ag7xxx_switch_reg_read(bus, 0x98, &data);
+       ret = ag7xxx_switch_reg_read(bus, 0x98, &data);
+       if (ret < 0)
+               return ret;
        data = val | (reg << 16) | (addr << 21) | BIT(30) | BIT(31);
-       ag7xxx_switch_reg_write(bus, 0x98, data);
+       ret = ag7xxx_switch_reg_write(bus, 0x98, data);
+       if (ret < 0)
+               return ret;
+
+       start = get_timer(0);
 
        /* Wait for operation to finish */
        do {
-               ag7xxx_switch_reg_read(bus, 0x98, &data);
+               ret = ag7xxx_switch_reg_read(bus, 0x98, &data);
+               if (ret < 0)
+                       return ret;
+
+               if (get_timer(start) > timeout_ms)
+                       return -ETIMEDOUT;
        } while (data & BIT(31));
 
        return data & 0xffff;
@@ -294,7 +383,11 @@ static int ag7xxx_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
 static int ag7xxx_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
                             u16 val)
 {
-       ag7xxx_mdio_rw(bus, addr, reg, val);
+       int ret;
+
+       ret = ag7xxx_mdio_rw(bus, addr, reg, val);
+       if (ret < 0)
+               return ret;
        return 0;
 }
 
@@ -475,13 +568,13 @@ static void ag7xxx_eth_stop(struct udevice *dev)
 
        /* Stop the TX DMA. */
        writel(0, priv->regs + AG7XXX_ETH_DMA_TX_CTRL);
-       wait_for_bit("ag7xxx", priv->regs + AG7XXX_ETH_DMA_TX_CTRL, ~0, 0,
-                    1000, 0);
+       wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_TX_CTRL, ~0, 0,
+                         1000, 0);
 
        /* Stop the RX DMA. */
        writel(0, priv->regs + AG7XXX_ETH_DMA_RX_CTRL);
-       wait_for_bit("ag7xxx", priv->regs + AG7XXX_ETH_DMA_RX_CTRL, ~0, 0,
-                    1000, 0);
+       wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_RX_CTRL, ~0, 0,
+                         1000, 0);
 }
 
 /*
@@ -564,10 +657,19 @@ static int ag7xxx_mii_setup(struct udevice *dev)
                        return 0;
        }
 
-       if (priv->model == AG7XXX_MODEL_AG934X) {
-               writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | 0x4,
+       if (priv->model == AG7XXX_MODEL_AG934X)
+               reg = 0x4;
+       else if (priv->model == AG7XXX_MODEL_AG953X)
+               reg = 0x2;
+       else if (priv->model == AG7XXX_MODEL_AG956X)
+               reg = 0x7;
+
+       if (priv->model == AG7XXX_MODEL_AG934X ||
+           priv->model == AG7XXX_MODEL_AG953X ||
+           priv->model == AG7XXX_MODEL_AG956X) {
+               writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | reg,
                       priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
-               writel(0x4, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
+               writel(reg, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
                return 0;
        }
 
@@ -664,14 +766,126 @@ static int ag933x_phy_setup_lan(struct udevice *dev)
        return 0;
 }
 
+static int ag953x_phy_setup_wan(struct udevice *dev)
+{
+       int ret;
+       u32 reg = 0;
+       struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
+
+       /* Set wan port connect to GE0 */
+       ret = ag7xxx_switch_reg_read(priv->bus, 0x8, &reg);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x8, reg | BIT(28));
+       if (ret)
+               return ret;
+
+       /* Configure switch port 4 (GMAC0) */
+       ret = ag7xxx_switch_write(priv->bus, 4, MII_BMCR, 0x9000);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int ag953x_phy_setup_lan(struct udevice *dev)
+{
+       struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
+       int i, ret;
+       u32 reg = 0;
+
+       /* Reset the switch */
+       ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0, reg | BIT(31));
+       if (ret)
+               return ret;
+
+       do {
+               ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
+               if (ret)
+                       return ret;
+       } while (reg & BIT(31));
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x100, 0x4e);
+       if (ret)
+               return ret;
+
+       /* Set GMII mode */
+       ret = ag7xxx_switch_reg_read(priv->bus, 0x4, &reg);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x4, reg | BIT(6));
+       if (ret)
+               return ret;
+
+       /* Configure switch ports 0...4 (GMAC1) */
+       for (i = 0; i < 5; i++) {
+               ret = ag7xxx_switch_write(priv->bus, i, MII_BMCR, 0x9000);
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; i < 5; i++) {
+               ret = ag7xxx_switch_reg_write(priv->bus, (i + 2) * 0x100, BIT(9));
+               if (ret)
+                       return ret;
+       }
+
+       /* QM Control */
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x38, 0xc000050e);
+       if (ret)
+               return ret;
+
+       /* Disable Atheros header */
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x104, 0x4004);
+       if (ret)
+               return ret;
+
+       /* Tag priority mapping */
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x70, 0xfa50);
+       if (ret)
+               return ret;
+
+       /* Enable ARP packets to the CPU */
+       ret = ag7xxx_switch_reg_read(priv->bus, 0x5c, &reg);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x5c, reg | 0x100000);
+       if (ret)
+               return ret;
+
+       /* Enable broadcast packets to the CPU */
+       ret = ag7xxx_switch_reg_read(priv->bus, 0x2c, &reg);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x2c, reg | BIT(25) | BIT(26));
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
 static int ag933x_phy_setup_reset_set(struct udevice *dev, int port)
 {
        struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
        int ret;
 
-       ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_ADVERTISE,
-                               ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
-                               ADVERTISE_PAUSE_ASYM);
+       if (priv->model == AG7XXX_MODEL_AG953X ||
+           priv->model == AG7XXX_MODEL_AG956X) {
+               ret = ag7xxx_switch_write(priv->bus, port, MII_ADVERTISE,
+                                       ADVERTISE_ALL);
+       } else {
+               ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_ADVERTISE,
+                                       ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
+                                       ADVERTISE_PAUSE_ASYM);
+       }
        if (ret)
                return ret;
 
@@ -680,8 +894,18 @@ static int ag933x_phy_setup_reset_set(struct udevice *dev, int port)
                                        ADVERTISE_1000FULL);
                if (ret)
                        return ret;
+       } else if (priv->model == AG7XXX_MODEL_AG956X) {
+               ret = ag7xxx_switch_write(priv->bus, port, MII_CTRL1000,
+                                         ADVERTISE_1000FULL);
+               if (ret)
+                       return ret;
        }
 
+       if (priv->model == AG7XXX_MODEL_AG953X ||
+           priv->model == AG7XXX_MODEL_AG956X)
+               return ag7xxx_switch_write(priv->bus, port, MII_BMCR,
+                                        BMCR_ANENABLE | BMCR_RESET);
+
        return ag7xxx_mdio_write(priv->bus, port, 0, MII_BMCR,
                                 BMCR_ANENABLE | BMCR_RESET);
 }
@@ -690,13 +914,24 @@ static int ag933x_phy_setup_reset_fin(struct udevice *dev, int port)
 {
        struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
        int ret;
+       u16 reg;
 
-       do {
-               ret = ag7xxx_mdio_read(priv->bus, port, 0, MII_BMCR);
-               if (ret < 0)
-                       return ret;
-               mdelay(10);
-       } while (ret & BMCR_RESET);
+       if (priv->model == AG7XXX_MODEL_AG953X ||
+           priv->model == AG7XXX_MODEL_AG956X) {
+               do {
+                       ret = ag7xxx_switch_read(priv->bus, port, MII_BMCR, &reg);
+                       if (ret < 0)
+                               return ret;
+                       mdelay(10);
+               } while (reg & BMCR_RESET);
+       } else {
+               do {
+                       ret = ag7xxx_mdio_read(priv->bus, port, 0, MII_BMCR);
+                       if (ret < 0)
+                               return ret;
+                       mdelay(10);
+               } while (ret & BMCR_RESET);
+       }
 
        return 0;
 }
@@ -705,10 +940,13 @@ static int ag933x_phy_setup_common(struct udevice *dev)
 {
        struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
        int i, ret, phymax;
+       u16 reg;
 
        if (priv->model == AG7XXX_MODEL_AG933X)
                phymax = 4;
-       else if (priv->model == AG7XXX_MODEL_AG934X)
+       else if (priv->model == AG7XXX_MODEL_AG934X ||
+               priv->model == AG7XXX_MODEL_AG953X ||
+               priv->model == AG7XXX_MODEL_AG956X)
                phymax = 5;
        else
                return -EINVAL;
@@ -723,7 +961,10 @@ static int ag933x_phy_setup_common(struct udevice *dev)
                        return ret;
 
                /* Read out link status */
-               ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR);
+               if (priv->model == AG7XXX_MODEL_AG953X)
+                       ret = ag7xxx_switch_read(priv->bus, phymax, MII_MIPSCR, &reg);
+               else
+                       ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR);
                if (ret < 0)
                        return ret;
 
@@ -745,7 +986,11 @@ static int ag933x_phy_setup_common(struct udevice *dev)
 
        for (i = 0; i < phymax; i++) {
                /* Read out link status */
-               ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR);
+               if (priv->model == AG7XXX_MODEL_AG953X ||
+                   priv->model == AG7XXX_MODEL_AG956X)
+                       ret = ag7xxx_switch_read(priv->bus, i, MII_MIPSCR, &reg);
+               else
+                       ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR);
                if (ret < 0)
                        return ret;
        }
@@ -807,6 +1052,63 @@ static int ag934x_phy_setup(struct udevice *dev)
        return 0;
 }
 
+static int ag956x_phy_setup(struct udevice *dev)
+{
+       struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
+       int i, ret;
+       u32 reg, ctrl;
+
+       ret = ag7xxx_switch_reg_read(priv->bus, 0x0, &reg);
+       if (ret)
+               return ret;
+       if ((reg & 0xffff) >= 0x1301)
+               ctrl = 0xc74164de;
+       else
+               ctrl = 0xc74164d0;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x4, BIT(7));
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0xe0, ctrl);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x624, 0x7f7f7f7f);
+       if (ret)
+               return ret;
+
+       /*
+        * Values suggested by the switch team when s17 in sgmii
+        * configuration. 0x10(S17_PWS_REG) = 0x602613a0
+        */
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x10, 0x602613a0);
+       if (ret)
+               return ret;
+
+       ret = ag7xxx_switch_reg_write(priv->bus, 0x7c, 0x0000007e);
+       if (ret)
+               return ret;
+
+       /* AR8337/AR8334 v1.0 fixup */
+       ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
+       if (ret)
+               return ret;
+       if ((reg & 0xffff) == 0x1301) {
+               for (i = 0; i < 5; i++) {
+                       /* Turn on Gigabit clock */
+                       ret = ag7xxx_switch_write(priv->bus, i, 0x1d, 0x3d);
+                       if (ret)
+                               return ret;
+                       ret = ag7xxx_switch_write(priv->bus, i, 0x1e, 0x6820);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
 static int ag7xxx_mac_probe(struct udevice *dev)
 {
        struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
@@ -824,8 +1126,15 @@ static int ag7xxx_mac_probe(struct udevice *dev)
                        ret = ag933x_phy_setup_wan(dev);
                else
                        ret = ag933x_phy_setup_lan(dev);
+       } else if (priv->model == AG7XXX_MODEL_AG953X) {
+               if (priv->interface == PHY_INTERFACE_MODE_RMII)
+                       ret = ag953x_phy_setup_wan(dev);
+               else
+                       ret = ag953x_phy_setup_lan(dev);
        } else if (priv->model == AG7XXX_MODEL_AG934X) {
                ret = ag934x_phy_setup(dev);
+       } else if (priv->model == AG7XXX_MODEL_AG956X) {
+               ret = ag956x_phy_setup(dev);
        } else {
                return -EINVAL;
        }
@@ -857,7 +1166,7 @@ static int ag7xxx_get_phy_iface_offset(struct udevice *dev)
 {
        int offset;
 
-       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev->of_offset, "phy");
+       offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), "phy");
        if (offset <= 0) {
                debug("%s: PHY OF node not found (ret=%i)\n", __func__, offset);
                return -EINVAL;
@@ -941,7 +1250,7 @@ static int ag7xxx_eth_ofdata_to_platdata(struct udevice *dev)
        const char *phy_mode;
        int ret;
 
-       pdata->iobase = dev_get_addr(dev);
+       pdata->iobase = devfdt_get_addr(dev);
        pdata->phy_interface = -1;
 
        /* Decoding of convoluted PHY wiring on Atheros MIPS. */
@@ -963,6 +1272,8 @@ static int ag7xxx_eth_ofdata_to_platdata(struct udevice *dev)
 static const struct udevice_id ag7xxx_eth_ids[] = {
        { .compatible = "qca,ag933x-mac", .data = AG7XXX_MODEL_AG933X },
        { .compatible = "qca,ag934x-mac", .data = AG7XXX_MODEL_AG934X },
+       { .compatible = "qca,ag953x-mac", .data = AG7XXX_MODEL_AG953X },
+       { .compatible = "qca,ag956x-mac", .data = AG7XXX_MODEL_AG956X },
        { }
 };