From patchwork Sat Mar 16 01:24:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rosy Song X-Patchwork-Id: 1057285 X-Patchwork-Delegate: daniel.schwierzeck@googlemail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=rosinson.com Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 44LlCV63GKz9s47 for ; Sat, 16 Mar 2019 12:26:30 +1100 (AEDT) Received: by lists.denx.de (Postfix, from userid 105) id 64C85C22190; Sat, 16 Mar 2019 01:26:27 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=UNPARSEABLE_RELAY autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id EB5A3C22198; Sat, 16 Mar 2019 01:25:08 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 68957C22195; Sat, 16 Mar 2019 01:24:59 +0000 (UTC) Received: from out20-1.mail.aliyun.com (out20-1.mail.aliyun.com [115.124.20.1]) by lists.denx.de (Postfix) with ESMTPS id 05CBBC221D3 for ; Sat, 16 Mar 2019 01:24:55 +0000 (UTC) X-Alimail-AntiSpam: AC=CONTINUE; BC=0.06436282|-1; CH=green; DM=CONTINUE|CONTINUE|true|0.0136231-0.00192508-0.984452; FP=0|0|0|0|0|-1|-1|-1; HT=e02c03306; MF=rosysong@rosinson.com; NM=1; PH=DS; RN=3; RT=3; SR=0; TI=SMTPD_---.E8iFwT9_1552699491; Received: from localhost.localdomain(mailfrom:rosysong@rosinson.com fp:SMTPD_---.E8iFwT9_1552699491) by smtp.aliyun-inc.com(10.147.44.129); Sat, 16 Mar 2019 09:24:52 +0800 From: rosysong@rosinson.com To: u-boot@lists.denx.de Date: Sat, 16 Mar 2019 09:24:50 +0800 Message-Id: <20190316012450.9313-1-rosysong@rosinson.com> X-Mailer: git-send-email 2.17.1 Subject: [U-Boot] [U-Boot, V5, PATCH 3/3] ag7xxx: add initial support for s17 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Rosy Song S17 ethernet support is for QCA8337N, which used on AP152 (QCA9563) board. It is a 7 ports GbE switch. Signed-off-by: Rosy Song Changes for v2-v3: - add more commit message for s17 Changes for v4-v5: - coding style cleanup --- drivers/net/ag7xxx.c | 139 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 123 insertions(+), 16 deletions(-) diff --git a/drivers/net/ag7xxx.c b/drivers/net/ag7xxx.c index 403eb64895..7f1dee4b3e 100644 --- a/drivers/net/ag7xxx.c +++ b/drivers/net/ag7xxx.c @@ -3,6 +3,7 @@ * Atheros AR71xx / AR9xxx GMAC driver * * Copyright (C) 2016 Marek Vasut + * Copyright (C) 2019 Rosy Song */ #include @@ -23,7 +24,8 @@ DECLARE_GLOBAL_DATA_PTR; enum ag7xxx_model { AG7XXX_MODEL_AG933X, AG7XXX_MODEL_AG934X, - AG7XXX_MODEL_AG953X + AG7XXX_MODEL_AG953X, + AG7XXX_MODEL_AG956X }; /* MAC Configuration 1 */ @@ -219,6 +221,7 @@ 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; @@ -226,18 +229,25 @@ static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val) 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); @@ -245,7 +255,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); @@ -260,24 +276,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 || 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 @@ -296,10 +322,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; @@ -626,9 +660,12 @@ static int ag7xxx_mii_setup(struct udevice *dev) 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_AG953X || + priv->model == AG7XXX_MODEL_AG956X) { writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | reg, priv->regs + AG7XXX_ETH_MII_MGMT_CFG); writel(reg, priv->regs + AG7XXX_ETH_MII_MGMT_CFG); @@ -839,7 +876,8 @@ static int ag933x_phy_setup_reset_set(struct udevice *dev, int port) struct ar7xxx_eth_priv *priv = dev_get_priv(dev); int ret; - if (priv->model == AG7XXX_MODEL_AG953X) { + if (priv->model == AG7XXX_MODEL_AG953X || + priv->model == AG7XXX_MODEL_AG956X) { ret = ag7xxx_switch_write(priv->bus, port, MII_ADVERTISE, ADVERTISE_ALL); } else { @@ -855,9 +893,15 @@ 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) + if (priv->model == AG7XXX_MODEL_AG953X || + priv->model == AG7XXX_MODEL_AG956X) return ag7xxx_switch_write(priv->bus, port, MII_BMCR, BMCR_ANENABLE | BMCR_RESET); @@ -871,7 +915,8 @@ static int ag933x_phy_setup_reset_fin(struct udevice *dev, int port) int ret; u16 reg; - if (priv->model == AG7XXX_MODEL_AG953X) { + if (priv->model == AG7XXX_MODEL_AG953X || + priv->model == AG7XXX_MODEL_AG956X) { do { ret = ag7xxx_switch_read(priv->bus, port, MII_BMCR, ®); if (ret < 0) @@ -899,7 +944,8 @@ static int ag933x_phy_setup_common(struct udevice *dev) if (priv->model == AG7XXX_MODEL_AG933X) phymax = 4; else if (priv->model == AG7XXX_MODEL_AG934X || - priv->model == AG7XXX_MODEL_AG953X) + priv->model == AG7XXX_MODEL_AG953X || + priv->model == AG7XXX_MODEL_AG956X) phymax = 5; else return -EINVAL; @@ -939,7 +985,8 @@ static int ag933x_phy_setup_common(struct udevice *dev) for (i = 0; i < phymax; i++) { /* Read out link status */ - if (priv->model == AG7XXX_MODEL_AG953X) + if (priv->model == AG7XXX_MODEL_AG953X || + priv->model == AG7XXX_MODEL_AG956X) ret = ag7xxx_switch_read(priv->bus, i, MII_MIPSCR, ®); else ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR); @@ -1004,6 +1051,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, ®); + 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, ®); + 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); @@ -1028,6 +1132,8 @@ static int ag7xxx_mac_probe(struct udevice *dev) 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; } @@ -1166,6 +1272,7 @@ 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 }, { } };