From f1f943e96c02bd09548df58b89c5fb41991a5532 Mon Sep 17 00:00:00 2001 From: Rosy Song Date: Tue, 5 Feb 2019 17:50:44 +0800 Subject: [PATCH] drivers: add ethernet support for qca953x in ag7xxx driver Signed-off-by: Rosy Song --- drivers/net/ag7xxx.c | 203 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 186 insertions(+), 17 deletions(-) diff --git a/drivers/net/ag7xxx.c b/drivers/net/ag7xxx.c index 8146c3170e..403eb64895 100644 --- a/drivers/net/ag7xxx.c +++ b/drivers/net/ag7xxx.c @@ -23,6 +23,7 @@ DECLARE_GLOBAL_DATA_PTR; enum ag7xxx_model { AG7XXX_MODEL_AG933X, AG7XXX_MODEL_AG934X, + AG7XXX_MODEL_AG953X }; /* MAC Configuration 1 */ @@ -99,8 +100,29 @@ enum ag7xxx_model { /* 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) @@ -200,7 +222,8 @@ static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val) 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) { @@ -239,7 +262,8 @@ static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val) u32 reg_temp; 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) { @@ -598,10 +622,16 @@ 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; + + if (priv->model == AG7XXX_MODEL_AG934X || + priv->model == AG7XXX_MODEL_AG953X) { + 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; } @@ -698,14 +728,125 @@ 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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, ®); + 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) { + 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; @@ -716,6 +857,10 @@ static int ag933x_phy_setup_reset_set(struct udevice *dev, int port) return ret; } + if (priv->model == AG7XXX_MODEL_AG953X) + 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); } @@ -724,13 +869,23 @@ 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) { + do { + ret = ag7xxx_switch_read(priv->bus, port, MII_BMCR, ®); + 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; } @@ -739,10 +894,12 @@ 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) phymax = 5; else return -EINVAL; @@ -757,7 +914,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, ®); + else + ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR); if (ret < 0) return ret; @@ -779,7 +939,10 @@ 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) + ret = ag7xxx_switch_read(priv->bus, i, MII_MIPSCR, ®); + else + ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR); if (ret < 0) return ret; } @@ -858,6 +1021,11 @@ 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 { @@ -997,6 +1165,7 @@ 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 }, { } }; -- 2.39.5