From patchwork Tue Apr 11 09:27:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 673005 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50B48C77B74 for ; Tue, 11 Apr 2023 09:29:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229763AbjDKJ2u (ORCPT ); Tue, 11 Apr 2023 05:28:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47756 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229714AbjDKJ20 (ORCPT ); Tue, 11 Apr 2023 05:28:26 -0400 Received: from smtpbguseast3.qq.com (smtpbguseast3.qq.com [54.243.244.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 47E8E10DA; Tue, 11 Apr 2023 02:28:22 -0700 (PDT) X-QQ-mid: bizesmtp91t1681205298tis7zqda Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 11 Apr 2023 17:28:17 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000000A0000000 X-QQ-FEAT: hoArX50alxESfU2Eg6x3EG/x0IMY3TM6Hp3J6l22/YCF2CY4lPABJ6OIli6lM jFh3UH6DnoDGzADAWVRrqtvxd8koo5ZAdJixlou3dJJQOyl6sCN1wgeBIUsczwlScAGNk9P 5qFqJEfqPhPDLQXTbWUhMrnifo8HMCPMwh3gqoBm2v+Rr3R4nXMQxOiNW2tPzLFZUX6+1Jw 5+3+AmEVJYL1gc3wfAuJ7L/oAftCkPqw5cjw1UGIyfjoX8Yi+S5xnpyvRkf+D0YAMG64Wh7 2kXsoIab3im81cxm1CQefA7WeaZjoCnR1OkVx1rbtaw3oBslaLAiOrk4NfNAo3yMUN8icsf Pe23RnJ3K29Kx2UU/UNIVG6KeaEtdZIk5l+LBDFyk93m7X5Le46xxxM+Tb1ubHyy0b32+O5 oVzx9ooRGRE= X-QQ-GoodBg: 2 X-BIZMAIL-ID: 15000991781746330880 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: linux-i2c@vger.kernel.org, linux-gpio@vger.kernel.org, mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next v2 2/6] net: txgbe: Implement I2C bus master driver Date: Tue, 11 Apr 2023 17:27:21 +0800 Message-Id: <20230411092725.104992-3-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230411092725.104992-1-jiawenwu@trustnetic.com> References: <20230411092725.104992-1-jiawenwu@trustnetic.com> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybglogicsvr:qybglogicsvr5 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Implement I2C bus driver to send and receive I2C messages. This I2C license the IP of Synopsys Designware, but without interrupt support on the hardware design. It seems that polling mode needs to be added in Synopsys Designware I2C driver. But currently it can only be driven by this I2C bus master driver. Signed-off-by: Jiawen Wu --- drivers/net/ethernet/wangxun/Kconfig | 1 + .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 153 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 23 +++ 3 files changed, 177 insertions(+) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index c9d88673d306..8cbf0dd48a2c 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -41,6 +41,7 @@ config TXGBE tristate "Wangxun(R) 10GbE PCI Express adapters support" depends on PCI select LIBWX + select I2C help This driver supports Wangxun(R) 10GbE PCI Express family of adapters. diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 86d5e0647d5e..2721da1625e0 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -2,9 +2,12 @@ /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ #include +#include +#include #include #include "../libwx/wx_type.h" +#include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_phy.h" @@ -67,6 +70,142 @@ static int txgbe_swnodes_register(struct txgbe *txgbe) return software_node_register_node_group(nodes->group); } +static void txgbe_i2c_start(struct wx *wx, u16 dev_addr) +{ + wr32(wx, TXGBE_I2C_ENABLE, 0); + + wr32(wx, TXGBE_I2C_CON, + (TXGBE_I2C_CON_MASTER_MODE | + TXGBE_I2C_CON_SPEED(1) | + TXGBE_I2C_CON_RESTART_EN | + TXGBE_I2C_CON_SLAVE_DISABLE)); + wr32(wx, TXGBE_I2C_TAR, dev_addr); + wr32(wx, TXGBE_I2C_SS_SCL_HCNT, 600); + wr32(wx, TXGBE_I2C_SS_SCL_LCNT, 600); + wr32(wx, TXGBE_I2C_RX_TL, 0); /* 1byte for rx full signal */ + wr32(wx, TXGBE_I2C_TX_TL, 4); + wr32(wx, TXGBE_I2C_SCL_STUCK_TIMEOUT, 0xFFFFFF); + wr32(wx, TXGBE_I2C_SDA_STUCK_TIMEOUT, 0xFFFFFF); + + wr32(wx, TXGBE_I2C_INTR_MASK, 0); + wr32(wx, TXGBE_I2C_ENABLE, 1); +} + +static int txgbe_i2c_poll_intr(struct wx *wx, u16 intr) +{ + u16 val; + + return read_poll_timeout(rd32, val, (val & intr) == intr, + 100, 1000, false, wx, + TXGBE_I2C_RAW_INTR_STAT); +} + +static int txgbe_read_i2c_bytes(struct wx *wx, u8 dev_addr, struct i2c_msg *msg) +{ + int err, i; + + txgbe_i2c_start(wx, msg->addr); + + for (i = 0; i < msg->len; i++) { + /* wait tx empty */ + err = txgbe_i2c_poll_intr(wx, TXGBE_I2C_INTR_STAT_TEMP); + if (err) + return err; + + /* read data */ + wr32(wx, TXGBE_I2C_DATA_CMD, + (dev_addr + i) | TXGBE_I2C_DATA_CMD_STOP); + wr32(wx, TXGBE_I2C_DATA_CMD, + TXGBE_I2C_DATA_CMD_READ | TXGBE_I2C_DATA_CMD_STOP); + + /* wait for read complete */ + err = txgbe_i2c_poll_intr(wx, TXGBE_I2C_INTR_STAT_RFUL); + if (err) + return err; + + msg->buf[i] = 0xFF & rd32(wx, TXGBE_I2C_DATA_CMD); + } + + return 0; +} + +static int txgbe_write_i2c_bytes(struct wx *wx, struct i2c_msg *msg) +{ + int err, i; + + txgbe_i2c_start(wx, msg->addr); + + for (i = 0; i < msg->len; i++) { + /* wait tx empty */ + err = txgbe_i2c_poll_intr(wx, TXGBE_I2C_INTR_STAT_TEMP); + if (err) + return err; + + /* write data */ + wr32(wx, TXGBE_I2C_DATA_CMD, msg->buf[i]); + if (i == (msg->len - 1)) + wr32(wx, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_STOP); + } + + return 0; +} + +static int txgbe_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msg, int num_msgs) +{ + struct wx *wx = i2c_get_adapdata(i2c_adap); + u8 dev_addr = msg[0].buf[0]; + int i, ret; + + for (i = 0; i < num_msgs; i++) { + if (msg[i].flags & I2C_M_RD) + ret = txgbe_read_i2c_bytes(wx, dev_addr, &msg[i]); + else + ret = txgbe_write_i2c_bytes(wx, &msg[i]); + + if (ret) + return ret; + } + + return num_msgs; +} + +static u32 txgbe_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm txgbe_i2c_algo = { + .master_xfer = txgbe_i2c_xfer, + .functionality = txgbe_i2c_func, +}; + +static int txgbe_i2c_adapter_add(struct txgbe *txgbe) +{ + struct pci_dev *pdev = txgbe->wx->pdev; + struct i2c_adapter *i2c_adap; + int ret; + + i2c_adap = devm_kzalloc(&pdev->dev, sizeof(*i2c_adap), GFP_KERNEL); + if (!i2c_adap) + return -ENOMEM; + + i2c_adap->owner = THIS_MODULE; + i2c_adap->algo = &txgbe_i2c_algo; + i2c_adap->dev.parent = &pdev->dev; + i2c_adap->dev.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]); + strscpy(i2c_adap->name, "txgbe_i2c", sizeof(i2c_adap->name)); + + i2c_set_adapdata(i2c_adap, txgbe->wx); + ret = i2c_add_adapter(i2c_adap); + if (ret) + return ret; + + txgbe->i2c_adap = i2c_adap; + + return 0; +} + int txgbe_init_phy(struct txgbe *txgbe) { int ret; @@ -77,10 +216,24 @@ int txgbe_init_phy(struct txgbe *txgbe) return ret; } + ret = txgbe_i2c_adapter_add(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret); + goto err; + } + return 0; + +err: + txgbe_remove_phy(txgbe); + + return ret; } void txgbe_remove_phy(struct txgbe *txgbe) { + if (txgbe->i2c_adap) + i2c_del_adapter(txgbe->i2c_adap); + software_node_unregister_node_group(txgbe->nodes.group); } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index d30684378f4e..6c02af196157 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -55,6 +55,28 @@ #define TXGBE_TS_CTL 0x10300 #define TXGBE_TS_CTL_EVAL_MD BIT(31) +/* I2C registers */ +#define TXGBE_I2C_CON 0x14900 /* I2C Control */ +#define TXGBE_I2C_CON_SLAVE_DISABLE BIT(6) +#define TXGBE_I2C_CON_RESTART_EN BIT(5) +#define TXGBE_I2C_CON_SPEED(_v) FIELD_PREP(GENMASK(2, 1), _v) +#define TXGBE_I2C_CON_MASTER_MODE BIT(0) +#define TXGBE_I2C_TAR 0x14904 /* I2C Target Address */ +#define TXGBE_I2C_DATA_CMD 0x14910 /* I2C Rx/Tx Data Buf and Cmd */ +#define TXGBE_I2C_DATA_CMD_STOP BIT(9) +#define TXGBE_I2C_DATA_CMD_READ BIT(8) +#define TXGBE_I2C_SS_SCL_HCNT 0x14914 +#define TXGBE_I2C_SS_SCL_LCNT 0x14918 +#define TXGBE_I2C_INTR_MASK 0x14930 /* I2C Interrupt Mask */ +#define TXGBE_I2C_RAW_INTR_STAT 0x14934 /* I2C Raw Interrupt Status */ +#define TXGBE_I2C_INTR_STAT_RFUL BIT(2) +#define TXGBE_I2C_INTR_STAT_TEMP BIT(4) +#define TXGBE_I2C_RX_TL 0x14938 /* I2C Receive FIFO Threshold */ +#define TXGBE_I2C_TX_TL 0x1493C /* I2C TX FIFO Threshold */ +#define TXGBE_I2C_ENABLE 0x1496C /* I2C Enable */ +#define TXGBE_I2C_SCL_STUCK_TIMEOUT 0x149AC +#define TXGBE_I2C_SDA_STUCK_TIMEOUT 0x149B0 + /* Part Number String Length */ #define TXGBE_PBANUM_LENGTH 32 @@ -139,6 +161,7 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct i2c_adapter *i2c_adap; }; #endif /* _TXGBE_TYPE_H_ */ From patchwork Tue Apr 11 09:27:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 673003 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC6ABC7619A for ; Tue, 11 Apr 2023 09:31:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229488AbjDKJa7 (ORCPT ); Tue, 11 Apr 2023 05:30:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49952 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229830AbjDKJa3 (ORCPT ); Tue, 11 Apr 2023 05:30:29 -0400 Received: from smtpbg151.qq.com (smtpbg151.qq.com [18.169.211.239]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3CE602139; Tue, 11 Apr 2023 02:30:16 -0700 (PDT) X-QQ-mid: bizesmtp91t1681205307tgjc20w4 Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 11 Apr 2023 17:28:26 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000000A0000000 X-QQ-FEAT: qOAV9bwDT/nUhpJ2+vAxwoxtj1KcxRDR1lg4F73jSSaq+11ZOdOXPqRb7UPfh +s9jlcHulBni1XkuItQd0F29I/LfPJL225c2J1bG4aqBU44jZHz+GaNs+JVDQxkVlbWsKXe DqICQFUJmSLwUhsBEMZrF+GyVEWj4aD/Ks5jO3U5Yk/943iIdKc0X+NZmVeFr2UWa/f9RG1 m4fFj+4G7hWnAzk1FmK7fKmOOdN2WmyLBSMjmJ4Qptfqe6DkGFiVStv4U6tY9oD2I6uIOO2 cfSgG2uWg8T9qD7L87+akNGh8XGqVLDQqhzcNDpqbanvEJn9AE5RODDvv3BaFrrJ6CoEMVG eJHbW/6HYvOcGk7q7zZM0jWXm8SoTXHGXTikXvNN61m48YUNNJVWYuunx0ZADI0QNqniSmv X-QQ-GoodBg: 2 X-BIZMAIL-ID: 8181199620835839703 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: linux-i2c@vger.kernel.org, linux-gpio@vger.kernel.org, mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next v2 5/6] net: txgbe: Implement phylink pcs Date: Tue, 11 Apr 2023 17:27:24 +0800 Message-Id: <20230411092725.104992-6-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230411092725.104992-1-jiawenwu@trustnetic.com> References: <20230411092725.104992-1-jiawenwu@trustnetic.com> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybglogicsvr:qybglogicsvr5 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Register MDIO bus for PCS layer, support 10GBASE-R and 1000BASE-X interfaces to the controller. Signed-off-by: Jiawen Wu --- drivers/net/ethernet/wangxun/Kconfig | 1 + .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 377 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 59 +++ 3 files changed, 437 insertions(+) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index d9cccdad8a53..9e374e9c3d9c 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -42,6 +42,7 @@ config TXGBE depends on PCI select GPIOLIB_IRQCHIP select GPIOLIB + select PHYLINK select LIBWX select I2C select SFP diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 42e66db6e9ff..123fa7ed9039 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -6,7 +6,9 @@ #include #include #include +#include #include +#include #include #include @@ -74,6 +76,375 @@ static int txgbe_swnodes_register(struct txgbe *txgbe) return software_node_register_node_group(nodes->group); } +static int pcs_read(struct txgbe *txgbe, int dev, u32 reg) +{ + return mdiodev_c45_read(txgbe->mdiodev, dev, reg); +} + +static int pcs_write(struct txgbe *txgbe, int dev, u32 reg, u16 val) +{ + return mdiodev_c45_write(txgbe->mdiodev, dev, reg, val); +} + +static int pma_read(struct txgbe *txgbe, u32 reg) +{ + return pcs_read(txgbe, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg); +} + +static int pma_write(struct txgbe *txgbe, u32 reg, u16 val) +{ + return pcs_write(txgbe, MDIO_MMD_PMAPMD, TXGBE_PMA_MMD + reg, val); +} + +static int txgbe_pcs_read(struct mii_bus *bus, int addr, int devnum, int regnum) +{ + struct wx *wx = bus->priv; + u32 offset, val; + + offset = devnum << 16 | regnum; + + /* Set the LAN port indicator to IDA_ADDR */ + wr32(wx, TXGBE_XPCS_IDA_ADDR, offset); + + /* Read the data from IDA_DATA register */ + val = rd32(wx, TXGBE_XPCS_IDA_DATA); + + return (u16)val; +} + +static int txgbe_pcs_write(struct mii_bus *bus, int addr, int devnum, int regnum, u16 val) +{ + struct wx *wx = bus->priv; + u32 offset; + + offset = devnum << 16 | regnum; + + /* Set the LAN port indicator to IDA_ADDR */ + wr32(wx, TXGBE_XPCS_IDA_ADDR, offset); + + /* Write the data to IDA_DATA register */ + wr32(wx, TXGBE_XPCS_IDA_DATA, val); + + return 0; +} + +static void txgbe_ephy_write(struct txgbe *txgbe, u32 addr, u32 data) +{ + struct wx *wx = txgbe->wx; + + /* Set the LAN port indicator to IDA_ADDR */ + wr32(wx, TXGBE_ETHPHY_IDA_ADDR, addr); + + /* Write the data to IDA_DATA register */ + wr32(wx, TXGBE_ETHPHY_IDA_DATA, data); +} + +static int txgbe_pcs_validate(struct phylink_pcs *pcs, + unsigned long *supported, + const struct phylink_link_state *state) +{ + /* When in 802.3z mode, we must have AN enabled */ + if (phy_interface_mode_is_8023z(state->interface) && + !phylink_test(state->advertising, Autoneg)) + return -EINVAL; + + return 0; +} + +static void txgbe_pma_config_10gbaser(struct txgbe *txgbe) +{ + u16 val; + + pcs_write(txgbe, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBR); + val = pcs_read(txgbe, MDIO_MMD_PMAPMD, MDIO_CTRL1); + val |= MDIO_CTRL1_SPEED10G; + pcs_write(txgbe, MDIO_MMD_PMAPMD, MDIO_CTRL1, val); + + pma_write(txgbe, TXGBE_MPLLA_CTL0, 0x21); + pma_write(txgbe, TXGBE_MPLLA_CTL3, 0); + val = pma_read(txgbe, TXGBE_TX_GENCTRL1); + val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTRL1_VBOOST_LVL); + pma_write(txgbe, TXGBE_TX_GENCTRL1, val); + pma_write(txgbe, TXGBE_MISC_CTL0, 0xCF00); + pma_write(txgbe, TXGBE_VCO_CAL_LD0, 0x549); + pma_write(txgbe, TXGBE_VCO_CAL_REF0, 0x29); + pma_write(txgbe, TXGBE_TX_RATE_CTL, 0); + pma_write(txgbe, TXGBE_RX_RATE_CTL, 0); + pma_write(txgbe, TXGBE_TX_GEN_CTL2, 0x300); + pma_write(txgbe, TXGBE_RX_GEN_CTL2, 0x300); + pma_write(txgbe, TXGBE_MPLLA_CTL2, 0x600); + + pma_write(txgbe, TXGBE_RX_EQ_CTL0, 0x45); + val = pma_read(txgbe, TXGBE_RX_EQ_ATTN_CTL); + val &= ~TXGBE_RX_EQ_ATTN_LVL0; + pma_write(txgbe, TXGBE_RX_EQ_ATTN_CTL, val); + pma_write(txgbe, TXGBE_DFE_TAP_CTL0, 0xBE); + val = pma_read(txgbe, TXGBE_AFE_DFE_ENABLE); + val &= ~(TXGBE_DFE_EN_0 | TXGBE_AFE_EN_0); + pma_write(txgbe, TXGBE_AFE_DFE_ENABLE, val); + val = pma_read(txgbe, TXGBE_RX_EQ_CTL4); + val &= ~TXGBE_RX_EQ_CTL4_CONT_ADAPT0; + pma_write(txgbe, TXGBE_RX_EQ_CTL4, val); +} + +static void txgbe_pma_config_1000basex(struct txgbe *txgbe) +{ + u16 val; + + pcs_write(txgbe, MDIO_MMD_PCS, MDIO_CTRL2, MDIO_PCS_CTRL2_10GBX); + pcs_write(txgbe, MDIO_MMD_PMAPMD, MDIO_CTRL1, 0); + pcs_write(txgbe, MDIO_MMD_VEND2, MDIO_CTRL1, + MDIO_PMA_CTRL1_SPEED1000 | MDIO_CTRL1_FULLDPLX); + + val = pma_read(txgbe, TXGBE_TX_GENCTRL1); + val = u16_replace_bits(val, 0x5, TXGBE_TX_GENCTRL1_VBOOST_LVL); + val &= ~TXGBE_TX_GENCTRL1_VBOOST_EN0; + pma_write(txgbe, TXGBE_TX_GENCTRL1, val); + pma_write(txgbe, TXGBE_MISC_CTL0, 0xCF00); + + pma_write(txgbe, TXGBE_RX_EQ_CTL0, 0x7706); + val = pma_read(txgbe, TXGBE_RX_EQ_ATTN_CTL); + val &= ~TXGBE_RX_EQ_ATTN_LVL0; + pma_write(txgbe, TXGBE_RX_EQ_ATTN_CTL, val); + pma_write(txgbe, TXGBE_DFE_TAP_CTL0, 0); + val = pma_read(txgbe, TXGBE_RX_GEN_CTL3); + val = u16_replace_bits(val, 0x4, TXGBE_RX_GEN_CTL3_LOS_TRSHLD0); + pma_write(txgbe, TXGBE_RX_EQ_ATTN_CTL, val); + + pma_write(txgbe, TXGBE_MPLLA_CTL0, 0x20); + pma_write(txgbe, TXGBE_MPLLA_CTL3, 0x46); + pma_write(txgbe, TXGBE_VCO_CAL_LD0, 0x540); + pma_write(txgbe, TXGBE_VCO_CAL_REF0, 0x2A); + pma_write(txgbe, TXGBE_AFE_DFE_ENABLE, 0); + pma_write(txgbe, TXGBE_RX_EQ_CTL4, 0x10); + pma_write(txgbe, TXGBE_TX_RATE_CTL, 0x3); + pma_write(txgbe, TXGBE_RX_RATE_CTL, 0x3); + pma_write(txgbe, TXGBE_TX_GEN_CTL2, 0x100); + pma_write(txgbe, TXGBE_RX_GEN_CTL2, 0x100); + pma_write(txgbe, TXGBE_MPLLA_CTL2, 0x200); + pcs_write(txgbe, MDIO_MMD_VEND2, TXGBE_MII_AN_CTRL, TXGBE_MII_AN_CTRL_MII); +} + +static void txgbe_set_an37_ability(struct txgbe *txgbe) +{ + u16 val; + + pcs_write(txgbe, MDIO_MMD_PCS, TXGBE_PCS_DIG_CTRL1, + TXGBE_PCS_DIG_CTRL1_EN_VSMMD1 | + TXGBE_PCS_DIG_CTRL1_CLS7_BP | + TXGBE_PCS_DIG_CTRL1_BYP_PWRUP); + pcs_write(txgbe, MDIO_MMD_VEND2, TXGBE_MII_AN_CTRL, + TXGBE_MII_AN_CTRL_MII | + TXGBE_MII_AN_CTRL_TXCFG | + TXGBE_MII_AN_CTRL_PCS_MODE(0) | + TXGBE_MII_AN_CTRL_INTR_EN); + pcs_write(txgbe, MDIO_MMD_VEND2, TXGBE_MII_DIG_CTRL1, + TXGBE_MII_DIG_CTRL1_MAC_AUTOSW); + val = pcs_read(txgbe, MDIO_MMD_VEND2, MDIO_CTRL1); + val |= BMCR_ANRESTART | BMCR_ANENABLE; + pcs_write(txgbe, MDIO_MMD_VEND2, MDIO_CTRL1, val); +} + +static void txgbe_setup_adv(struct txgbe *txgbe, phy_interface_t interface, + const unsigned long *advertising) +{ + int adv; + + adv = phylink_mii_c22_pcs_encode_advertisement(interface, + advertising); + if (adv > 0) + mdiodev_c45_modify(txgbe->mdiodev, MDIO_MMD_VEND2, MII_ADVERTISE, + 0xffff, adv); +} + +static int txgbe_pcs_config(struct phylink_pcs *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct txgbe *txgbe = container_of(pcs, struct txgbe, pcs); + struct wx *wx = txgbe->wx; + int ret, val; + + if (interface == txgbe->interface) + goto out; + + /* Wait xpcs power-up good */ + ret = read_poll_timeout(pcs_read, val, + (val & TXGBE_PCS_DIG_STS_PSEQ_ST) == + TXGBE_PCS_DIG_STS_PSEQ_ST_GOOD, + 10000, 1000000, false, + txgbe, MDIO_MMD_PCS, TXGBE_PCS_DIG_STS); + if (ret < 0) { + wx_err(wx, "xpcs power-up timeout.\n"); + return ret; + } + + /* Disable xpcs AN-73 */ + pcs_write(txgbe, MDIO_MMD_AN, MDIO_CTRL1, 0); + + /* Disable PHY MPLLA for eth mode change(after ECO) */ + txgbe_ephy_write(txgbe, TXGBE_SUP_DIG_MPLLA_OVRD_IN_0, 0x243A); + WX_WRITE_FLUSH(wx); + usleep_range(1000, 2000); + + /* Set the eth change_mode bit first in mis_rst register + * for corresponding LAN port + */ + wr32(wx, TXGBE_MIS_RST, TXGBE_MIS_RST_LAN_ETH_MODE(wx->bus.func)); + + switch (interface) { + case PHY_INTERFACE_MODE_10GBASER: + txgbe_pma_config_10gbaser(txgbe); + break; + case PHY_INTERFACE_MODE_1000BASEX: + txgbe_pma_config_1000basex(txgbe); + break; + default: + break; + } + + pcs_write(txgbe, MDIO_MMD_PCS, TXGBE_PCS_DIG_CTRL1, + TXGBE_PCS_DIG_CTRL1_VR_RST | TXGBE_PCS_DIG_CTRL1_EN_VSMMD1); + /* wait phy initialization done */ + ret = read_poll_timeout(pcs_read, val, + !(val & TXGBE_PCS_DIG_CTRL1_VR_RST), + 100000, 10000000, false, + txgbe, MDIO_MMD_PCS, TXGBE_PCS_DIG_CTRL1); + if (ret < 0) + wx_err(wx, "PHY initialization timeout.\n"); + + txgbe->interface = interface; + +out: + if (interface == PHY_INTERFACE_MODE_1000BASEX) { + txgbe_setup_adv(txgbe, interface, advertising); + txgbe_set_an37_ability(txgbe); + } + + return ret; +} + +static void txgbe_pcs_get_state_10gbr(struct txgbe *txgbe, + struct phylink_link_state *state) +{ + int ret; + + state->link = false; + + ret = pcs_read(txgbe, MDIO_MMD_PCS, MDIO_STAT1); + if (ret < 0) + return; + + if (ret & MDIO_STAT1_LSTATUS) + state->link = true; + + if (state->link) { + state->pause = MLO_PAUSE_TX | MLO_PAUSE_RX; + state->duplex = DUPLEX_FULL; + state->speed = SPEED_10000; + } +} + +static void txgbe_pcs_get_state_1000bx(struct txgbe *txgbe, + struct phylink_link_state *state) +{ + int lpa, bmsr, an_intr; + + /* Reset link state */ + state->link = false; + + lpa = pcs_read(txgbe, MDIO_MMD_VEND2, MII_LPA); + if (lpa < 0 || lpa & LPA_RFAULT) { + wx_err(txgbe->wx, "read pcs lpa error: %d\n", lpa); + return; + } + + bmsr = pcs_read(txgbe, MDIO_MMD_VEND2, MII_BMSR); + if (bmsr < 0) { + wx_err(txgbe->wx, "read pcs lpa error: %d\n", bmsr); + return; + } + + /* Clear AN complete interrupt */ + an_intr = pcs_read(txgbe, MDIO_MMD_VEND2, TXGBE_MII_AN_INTR); + if (an_intr & TXGBE_MII_AN_INTR_CL37_CMPLT) { + an_intr &= ~TXGBE_MII_AN_INTR_CL37_CMPLT; + pcs_write(txgbe, MDIO_MMD_VEND2, TXGBE_MII_AN_INTR, an_intr); + } + + phylink_mii_c22_pcs_decode_state(state, bmsr, lpa); +} + +static void txgbe_pcs_get_state(struct phylink_pcs *pcs, + struct phylink_link_state *state) +{ + struct txgbe *txgbe = container_of(pcs, struct txgbe, pcs); + + switch (state->interface) { + case PHY_INTERFACE_MODE_10GBASER: + txgbe_pcs_get_state_10gbr(txgbe, state); + return; + case PHY_INTERFACE_MODE_1000BASEX: + txgbe_pcs_get_state_1000bx(txgbe, state); + return; + default: + return; + } +} + +static void txgbe_pcs_an_restart(struct phylink_pcs *pcs) +{ + struct txgbe *txgbe = container_of(pcs, struct txgbe, pcs); + + mdiodev_c45_modify(txgbe->mdiodev, MDIO_MMD_VEND2, MDIO_CTRL1, + BMCR_ANRESTART, BMCR_ANRESTART); +} + +static const struct phylink_pcs_ops txgbe_pcs_ops = { + .pcs_validate = txgbe_pcs_validate, + .pcs_config = txgbe_pcs_config, + .pcs_get_state = txgbe_pcs_get_state, + .pcs_an_restart = txgbe_pcs_an_restart, +}; + +static int txgbe_mdio_pcs_init(struct txgbe *txgbe) +{ + struct mdio_device *mdiodev; + struct wx *wx = txgbe->wx; + struct mii_bus *mii_bus; + struct pci_dev *pdev; + int ret = 0; + + pdev = wx->pdev; + + mii_bus = devm_mdiobus_alloc(&pdev->dev); + if (!mii_bus) + return -ENOMEM; + + mii_bus->name = "txgbe_pcs_mdio_bus"; + mii_bus->read_c45 = &txgbe_pcs_read; + mii_bus->write_c45 = &txgbe_pcs_write; + mii_bus->parent = &pdev->dev; + mii_bus->phy_mask = ~0; + mii_bus->priv = wx; + snprintf(mii_bus->id, MII_BUS_ID_SIZE, "txgbe_pcs-%x", + (pdev->bus->number << 8) | pdev->devfn); + + ret = devm_mdiobus_register(&pdev->dev, mii_bus); + if (ret) + return ret; + + mdiodev = mdio_device_create(mii_bus, 0); + if (IS_ERR(mdiodev)) + return PTR_ERR(mdiodev); + + txgbe->mdiodev = mdiodev; + txgbe->pcs.ops = &txgbe_pcs_ops; + + return 0; +} + static void txgbe_i2c_start(struct wx *wx, u16 dev_addr) { wr32(wx, TXGBE_I2C_ENABLE, 0); @@ -457,6 +828,12 @@ int txgbe_init_phy(struct txgbe *txgbe) return ret; } + ret = txgbe_mdio_pcs_init(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init mdio pcs: %d\n", ret); + goto err; + } + ret = txgbe_i2c_adapter_add(txgbe); if (ret) { wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 58b0054ae59c..d83225b4e34e 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -5,6 +5,7 @@ #define _TXGBE_TYPE_H_ #include +#include /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 @@ -43,6 +44,8 @@ /**************** SP Registers ****************************/ /* chip control Registers */ +#define TXGBE_MIS_RST 0x1000C +#define TXGBE_MIS_RST_LAN_ETH_MODE(_i) BIT((_i) + 29) #define TXGBE_MIS_PRB_CTL 0x10010 #define TXGBE_MIS_PRB_CTL_LAN_UP(_i) BIT(1 - (_i)) /* FMGR Registers */ @@ -102,6 +105,59 @@ #define TXGBE_I2C_SCL_STUCK_TIMEOUT 0x149AC #define TXGBE_I2C_SDA_STUCK_TIMEOUT 0x149B0 +/************************************** ETH PHY ******************************/ +#define TXGBE_XPCS_IDA_ADDR 0x13000 +#define TXGBE_XPCS_IDA_DATA 0x13004 +#define TXGBE_ETHPHY_IDA_ADDR 0x13008 +#define TXGBE_ETHPHY_IDA_DATA 0x1300C +/* PHY Registers */ +#define TXGBE_SUP_DIG_MPLLA_OVRD_IN_0 0x4 +/* Vendor Specific PCS MMD Registers */ +#define TXGBE_PCS_DIG_CTRL1 0x8000 +#define TXGBE_PCS_DIG_CTRL1_VR_RST BIT(15) +#define TXGBE_PCS_DIG_CTRL1_EN_VSMMD1 BIT(13) +#define TXGBE_PCS_DIG_CTRL1_CLS7_BP BIT(12) +#define TXGBE_PCS_DIG_CTRL1_BYP_PWRUP BIT(1) +#define TXGBE_PCS_DIG_STS 0x8010 +#define TXGBE_PCS_DIG_STS_PSEQ_ST GENMASK(4, 2) +#define TXGBE_PCS_DIG_STS_PSEQ_ST_GOOD FIELD_PREP(GENMASK(4, 2), 0x4) +/* Vendor Specific MII MMD Standard Registers */ +#define TXGBE_MII_DIG_CTRL1 0x8000 +#define TXGBE_MII_DIG_CTRL1_MAC_AUTOSW BIT(9) +#define TXGBE_MII_AN_CTRL 0x8001 +#define TXGBE_MII_AN_CTRL_MII BIT(8) +#define TXGBE_MII_AN_CTRL_TXCFG BIT(3) +#define TXGBE_MII_AN_CTRL_PCS_MODE(_v) FIELD_PREP(GENMASK(2, 1), _v) +#define TXGBE_MII_AN_CTRL_INTR_EN BIT(0) +#define TXGBE_MII_AN_INTR 0x8002 +#define TXGBE_MII_AN_INTR_CL37_CMPLT BIT(0) +/* Vendor Specific PMA MMD Registers */ +#define TXGBE_PMA_MMD 0x8020 +#define TXGBE_TX_GENCTRL1 0x11 +#define TXGBE_TX_GENCTRL1_VBOOST_LVL GENMASK(10, 8) +#define TXGBE_TX_GENCTRL1_VBOOST_EN0 BIT(4) +#define TXGBE_TX_GEN_CTL2 0x12 +#define TXGBE_TX_RATE_CTL 0x14 +#define TXGBE_RX_GEN_CTL2 0x32 +#define TXGBE_RX_GEN_CTL3 0x33 +#define TXGBE_RX_GEN_CTL3_LOS_TRSHLD0 GENMASK(2, 0) +#define TXGBE_RX_RATE_CTL 0x34 +#define TXGBE_RX_EQ_ATTN_CTL 0x37 +#define TXGBE_RX_EQ_ATTN_LVL0 GENMASK(2, 0) +#define TXGBE_RX_EQ_CTL0 0x38 +#define TXGBE_RX_EQ_CTL4 0x3C +#define TXGBE_RX_EQ_CTL4_CONT_ADAPT0 BIT(0) +#define TXGBE_AFE_DFE_ENABLE 0x3D +#define TXGBE_DFE_EN_0 BIT(4) +#define TXGBE_AFE_EN_0 BIT(0) +#define TXGBE_DFE_TAP_CTL0 0x3E +#define TXGBE_MPLLA_CTL0 0x51 +#define TXGBE_MPLLA_CTL2 0x53 +#define TXGBE_MPLLA_CTL3 0x57 +#define TXGBE_MISC_CTL0 0x70 +#define TXGBE_VCO_CAL_LD0 0x72 +#define TXGBE_VCO_CAL_REF0 0x76 + /* Part Number String Length */ #define TXGBE_PBANUM_LENGTH 32 @@ -186,9 +242,12 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct mdio_device *mdiodev; + struct phylink_pcs pcs; struct i2c_adapter *i2c_adap; struct gpio_chip *gpio; struct platform_device *sfp_dev; + phy_interface_t interface; u32 gpio_orig; }; From patchwork Tue Apr 11 09:27:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 673004 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1D666C7619A for ; Tue, 11 Apr 2023 09:29:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229922AbjDKJ3X (ORCPT ); Tue, 11 Apr 2023 05:29:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229775AbjDKJ2t (ORCPT ); Tue, 11 Apr 2023 05:28:49 -0400 Received: from smtpbg151.qq.com (smtpbg151.qq.com [18.169.211.239]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2AB5E44; Tue, 11 Apr 2023 02:28:45 -0700 (PDT) X-QQ-mid: bizesmtp91t1681205310tx0e5001 Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 11 Apr 2023 17:28:29 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000000A0000000 X-QQ-FEAT: fs34Pe/+C2QCRbWdmZLGnSZ5LsQa3Q5fOAQ3B8m9qsXuZW7IG2XNFi71fPPvM 7G5tsoffnXjT/MO+u5YZ9R7gBEe5CakXr1cWTs2y0flDQKFgp6B8vDb8ijPMfcD/XrbCHJL YZMVnkYcaNSYpfBm4XdIsstRiY2GYZ+Tek7Ty0of4BySFkJl7KJJVEA4tyIcRsDD0nSYVOL b1jmsILrW+IvVzUBmkuVlCrahq2Q80z5DovOHf3HA8FVI20P5duOOgEMo+ltQ+CX5+32TKc Nlw6g8nH9MLJGcaJH7TY+az0YHkR3FSI4alODXh6kM5CvDIhSWOTPxxVHZWryWrcZxBB15U wz0eZnsp4XTR/MsrZhB2dg73K0Ltyyy0ptVD7HA76rgYEoXVzl9Mg9C/dZmvJzADyw4TiwT ejAWWVn8wZSFXrWw/UKdbQ== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 15283253318957034505 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: linux-i2c@vger.kernel.org, linux-gpio@vger.kernel.org, mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next v2 6/6] net: txgbe: Support phylink MAC layer Date: Tue, 11 Apr 2023 17:27:25 +0800 Message-Id: <20230411092725.104992-7-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230411092725.104992-1-jiawenwu@trustnetic.com> References: <20230411092725.104992-1-jiawenwu@trustnetic.com> MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:trustnetic.com:qybglogicsvr:qybglogicsvr5 Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org Add phylink support to Wangxun 10Gb Ethernet controller, for the 10GBASE-R and 1000BASE-X interfaces. Signed-off-by: Jiawen Wu --- .../ethernet/wangxun/txgbe/txgbe_ethtool.c | 34 ++++++ .../net/ethernet/wangxun/txgbe/txgbe_main.c | 19 ++- .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 111 +++++++++++++++++- .../net/ethernet/wangxun/txgbe/txgbe_type.h | 5 + 4 files changed, 156 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c index d914e9a05404..43ca84c90637 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c @@ -6,11 +6,45 @@ #include #include "../libwx/wx_ethtool.h" +#include "../libwx/wx_type.h" +#include "txgbe_type.h" #include "txgbe_ethtool.h" +static int txgbe_nway_reset(struct net_device *netdev) +{ + struct wx *wx = netdev_priv(netdev); + struct txgbe *txgbe; + + txgbe = (struct txgbe *)wx->priv; + return phylink_ethtool_nway_reset(txgbe->phylink); +} + +static int txgbe_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) +{ + struct wx *wx = netdev_priv(netdev); + struct txgbe *txgbe; + + txgbe = (struct txgbe *)wx->priv; + return phylink_ethtool_ksettings_get(txgbe->phylink, cmd); +} + +static int txgbe_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *cmd) +{ + struct wx *wx = netdev_priv(netdev); + struct txgbe *txgbe; + + txgbe = (struct txgbe *)wx->priv; + return phylink_ethtool_ksettings_set(txgbe->phylink, cmd); +} + static const struct ethtool_ops txgbe_ethtool_ops = { .get_drvinfo = wx_get_drvinfo, + .nway_reset = txgbe_nway_reset, .get_link = ethtool_op_get_link, + .get_link_ksettings = txgbe_get_link_ksettings, + .set_link_ksettings = txgbe_set_link_ksettings, }; void txgbe_set_ethtool_ops(struct net_device *netdev) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index d8108ab30818..f640ff1a084e 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -204,7 +205,7 @@ static int txgbe_request_irq(struct wx *wx) static void txgbe_up_complete(struct wx *wx) { - u32 reg; + struct txgbe *txgbe = (struct txgbe *)wx->priv; wx_control_hw(wx, true); wx_configure_vectors(wx); @@ -213,24 +214,16 @@ static void txgbe_up_complete(struct wx *wx) smp_mb__before_atomic(); wx_napi_enable_all(wx); + phylink_start(txgbe->phylink); + /* clear any pending interrupts, may auto mask */ rd32(wx, WX_PX_IC(0)); rd32(wx, WX_PX_IC(1)); rd32(wx, WX_PX_MISC_IC); txgbe_irq_enable(wx, true); - /* Configure MAC Rx and Tx when link is up */ - reg = rd32(wx, WX_MAC_RX_CFG); - wr32(wx, WX_MAC_RX_CFG, reg); - wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); - reg = rd32(wx, WX_MAC_WDG_TIMEOUT); - wr32(wx, WX_MAC_WDG_TIMEOUT, reg); - reg = rd32(wx, WX_MAC_TX_CFG); - wr32(wx, WX_MAC_TX_CFG, (reg & ~WX_MAC_TX_CFG_SPEED_MASK) | WX_MAC_TX_CFG_SPEED_10G); - /* enable transmits */ netif_tx_start_all_queues(wx->netdev); - netif_carrier_on(wx->netdev); } static void txgbe_reset(struct wx *wx) @@ -264,7 +257,6 @@ static void txgbe_disable_device(struct wx *wx) wx_disable_rx_queue(wx, wx->rx_ring[i]); netif_tx_stop_all_queues(netdev); - netif_carrier_off(netdev); netif_tx_disable(netdev); wx_irq_disable(wx); @@ -295,8 +287,11 @@ static void txgbe_disable_device(struct wx *wx) static void txgbe_down(struct wx *wx) { + struct txgbe *txgbe = (struct txgbe *)wx->priv; + txgbe_disable_device(wx); txgbe_reset(wx); + phylink_stop(txgbe->phylink); wx_clean_all_tx_rings(wx); wx_clean_all_rx_rings(wx); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index 123fa7ed9039..84dc3e850036 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -13,6 +13,7 @@ #include #include "../libwx/wx_type.h" +#include "../libwx/wx_lib.h" #include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_phy.h" @@ -445,6 +446,98 @@ static int txgbe_mdio_pcs_init(struct txgbe *txgbe) return 0; } +static struct phylink_pcs *txgbe_phylink_mac_select(struct phylink_config *config, + phy_interface_t interface) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + struct txgbe *txgbe = (struct txgbe *)wx->priv; + + return &txgbe->pcs; +} + +static void txgbe_mac_config(struct phylink_config *config, unsigned int mode, + const struct phylink_link_state *state) +{ +} + +static void txgbe_mac_link_down(struct phylink_config *config, + unsigned int mode, phy_interface_t interface) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + + wr32m(wx, WX_MAC_TX_CFG, WX_MAC_TX_CFG_TE, 0); +} + +static void txgbe_mac_link_up(struct phylink_config *config, + struct phy_device *phy, + unsigned int mode, phy_interface_t interface, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct wx *wx = netdev_priv(to_net_dev(config->dev)); + u32 txcfg, rxcfg, wdg; + + txcfg = rd32(wx, WX_MAC_TX_CFG); + txcfg &= ~WX_MAC_TX_CFG_SPEED_MASK; + + switch (speed) { + case SPEED_10000: + txcfg |= WX_MAC_TX_CFG_SPEED_10G; + break; + case SPEED_1000: + case SPEED_100: + case SPEED_10: + txcfg |= WX_MAC_TX_CFG_SPEED_1G; + break; + default: + break; + } + + wr32(wx, WX_MAC_TX_CFG, txcfg | WX_MAC_TX_CFG_TE); + + /* Re configure MAC Rx */ + rxcfg = rd32(wx, WX_MAC_RX_CFG); + wr32(wx, WX_MAC_RX_CFG, rxcfg); + wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR); + wdg = rd32(wx, WX_MAC_WDG_TIMEOUT); + wr32(wx, WX_MAC_WDG_TIMEOUT, wdg); +} + +static const struct phylink_mac_ops txgbe_mac_ops = { + .mac_select_pcs = txgbe_phylink_mac_select, + .mac_config = txgbe_mac_config, + .mac_link_down = txgbe_mac_link_down, + .mac_link_up = txgbe_mac_link_up, +}; + +static int txgbe_phylink_init(struct txgbe *txgbe) +{ + struct phylink_config *config; + struct fwnode_handle *fwnode; + struct wx *wx = txgbe->wx; + phy_interface_t phy_mode; + struct phylink *phylink; + + config = devm_kzalloc(&wx->pdev->dev, sizeof(*config), GFP_KERNEL); + if (!config) + return -ENOMEM; + + config->dev = &wx->netdev->dev; + config->type = PHYLINK_NETDEV; + config->mac_capabilities = MAC_10000FD | MAC_1000FD | MAC_SYM_PAUSE | MAC_ASYM_PAUSE; + phy_mode = PHY_INTERFACE_MODE_10GBASER; + __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces); + __set_bit(PHY_INTERFACE_MODE_1000BASEX, config->supported_interfaces); + fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_PHYLINK]); + phylink = phylink_create(config, fwnode, phy_mode, &txgbe_mac_ops); + if (IS_ERR(phylink)) + return PTR_ERR(phylink); + + txgbe->phylink = phylink; + + return 0; +} + static void txgbe_i2c_start(struct wx *wx, u16 dev_addr) { wr32(wx, TXGBE_I2C_ENABLE, 0); @@ -728,7 +821,9 @@ static void txgbe_irq_handler(struct irq_desc *desc) struct gpio_chip *gc = txgbe->gpio; irq_hw_number_t hwirq; unsigned long gpioirq; - u32 gpio; + u32 gpio, eicr, reg; + + eicr = wx_misc_isb(wx, WX_ISB_MISC); chained_irq_enter(chip, desc); @@ -744,6 +839,12 @@ static void txgbe_irq_handler(struct irq_desc *desc) chained_irq_exit(chip, desc); + if (eicr & (TXGBE_PX_MISC_ETH_LK | TXGBE_PX_MISC_ETH_LKDN | + TXGBE_PX_MISC_ETH_AN)) { + reg = rd32(wx, TXGBE_CFG_PORT_ST); + phylink_mac_change(txgbe->phylink, !!(reg & TXGBE_CFG_PORT_ST_LINK_UP)); + } + /* unmask interrupt */ if (netif_running(wx->netdev)) wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); @@ -834,6 +935,12 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err; } + ret = txgbe_phylink_init(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init phylink\n"); + goto err; + } + ret = txgbe_i2c_adapter_add(txgbe); if (ret) { wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret); @@ -862,6 +969,8 @@ int txgbe_init_phy(struct txgbe *txgbe) void txgbe_remove_phy(struct txgbe *txgbe) { + if (txgbe->phylink) + phylink_destroy(txgbe->phylink); if (txgbe->sfp_dev) platform_device_unregister(txgbe->sfp_dev); if (txgbe->i2c_adap) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index d83225b4e34e..45fb887aaf6d 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -83,6 +83,10 @@ TXGBE_PX_MISC_INT_ERR | \ TXGBE_PX_MISC_GPIO) +/* Port cfg registers */ +#define TXGBE_CFG_PORT_ST 0x14404 +#define TXGBE_CFG_PORT_ST_LINK_UP BIT(0) + /* I2C registers */ #define TXGBE_I2C_CON 0x14900 /* I2C Control */ #define TXGBE_I2C_CON_SLAVE_DISABLE BIT(6) @@ -244,6 +248,7 @@ struct txgbe { struct txgbe_nodes nodes; struct mdio_device *mdiodev; struct phylink_pcs pcs; + struct phylink *phylink; struct i2c_adapter *i2c_adap; struct gpio_chip *gpio; struct platform_device *sfp_dev;