From patchwork Tue Apr 11 09:27:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 13207254 X-Patchwork-Delegate: kuba@kernel.org 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 9ED0BC77B77 for ; Tue, 11 Apr 2023 09:29:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229765AbjDKJ2v (ORCPT ); Tue, 11 Apr 2023 05:28:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47680 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229751AbjDKJ2V (ORCPT ); Tue, 11 Apr 2023 05:28:21 -0400 Received: from smtpbgjp3.qq.com (smtpbgjp3.qq.com [54.92.39.34]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 54EB82683; Tue, 11 Apr 2023 02:28:19 -0700 (PDT) X-QQ-mid: bizesmtp91t1681205295t0e3gu1c Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 11 Apr 2023 17:28:14 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000000A0000000 X-QQ-FEAT: iBxuBmNAXy1slOmqKzYjXbxjNpuTE/rrMsWViLgpQVLn9YAuADygLyKRpPhjM BCRnRToI5UoCC0LPynNvn4fNUKMeayYGI9gl0RM2q9SGNWV7dYLDh91al1Eu/am0l1qsftS aZgZwmH3he6QO5QRPvk+MHgDTDCqeJj9pNdr7S1dGglbZoIEarmmgLBm6rgPVwioRnjUWVM v4vs842QgRU9jli8vRKq++9WKEim8VrxgceqBI7fImQmGh0xE+9ODqK+tyRkb9Uvj9yRcGS ybwr7laloRHxdOaAo6RjqemjJ0Yl8+pqcE0gb7CrWqiBKZ4nzl6b6Ays3IJ4Ck7sHwbEd+L mbpCObBaAUZ54Z/RSTZp7uRU3o4AHs0LSApZBslmGoA0hP87lKhiGh4h5FeaL/hSMujnrNd Yn2YQELRRzeA9sVJ4dWhRg== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 15386639139174796298 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 1/6] net: txgbe: Add software nodes to support phylink Date: Tue, 11 Apr 2023 17:27:20 +0800 Message-Id: <20230411092725.104992-2-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: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Register software nodes for GPIO, I2C, SFP and PHYLINK. Define the device properties. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn --- drivers/net/ethernet/wangxun/libwx/wx_type.h | 1 + drivers/net/ethernet/wangxun/txgbe/Makefile | 1 + .../net/ethernet/wangxun/txgbe/txgbe_main.c | 19 +++- .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 86 +++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_phy.h | 10 +++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 42 +++++++++ 6 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c create mode 100644 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 32f952d93009..97bce855bc60 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -611,6 +611,7 @@ enum wx_isb_idx { struct wx { u8 __iomem *hw_addr; + void *priv; struct pci_dev *pdev; struct net_device *netdev; struct wx_bus_info bus; diff --git a/drivers/net/ethernet/wangxun/txgbe/Makefile b/drivers/net/ethernet/wangxun/txgbe/Makefile index 6db14a2cb2d0..7507f762edfe 100644 --- a/drivers/net/ethernet/wangxun/txgbe/Makefile +++ b/drivers/net/ethernet/wangxun/txgbe/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_TXGBE) += txgbe.o txgbe-objs := txgbe_main.o \ txgbe_hw.o \ + txgbe_phy.o \ txgbe_ethtool.o diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 5b8a121fb496..5a5e7620e9f8 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -15,6 +15,7 @@ #include "../libwx/wx_hw.h" #include "txgbe_type.h" #include "txgbe_hw.h" +#include "txgbe_phy.h" #include "txgbe_ethtool.h" char txgbe_driver_name[] = "txgbe"; @@ -513,6 +514,7 @@ static int txgbe_probe(struct pci_dev *pdev, struct net_device *netdev; int err, expected_gts; struct wx *wx = NULL; + struct txgbe *txgbe; u16 eeprom_verh = 0, eeprom_verl = 0, offset = 0; u16 eeprom_cfg_blkh = 0, eeprom_cfg_blkl = 0; @@ -663,10 +665,21 @@ static int txgbe_probe(struct pci_dev *pdev, "0x%08x", etrack_id); } - err = register_netdev(netdev); + txgbe = devm_kzalloc(&pdev->dev, sizeof(*txgbe), GFP_KERNEL); + if (!txgbe) + return -ENOMEM; + + txgbe->wx = wx; + wx->priv = txgbe; + + err = txgbe_init_phy(txgbe); if (err) goto err_release_hw; + err = register_netdev(netdev); + if (err) + goto err_remove_phy; + pci_set_drvdata(pdev, wx); netif_tx_stop_all_queues(netdev); @@ -694,6 +707,8 @@ static int txgbe_probe(struct pci_dev *pdev, return 0; +err_remove_phy: + txgbe_remove_phy(txgbe); err_release_hw: wx_clear_interrupt_scheme(wx); wx_control_hw(wx, false); @@ -724,6 +739,8 @@ static void txgbe_remove(struct pci_dev *pdev) netdev = wx->netdev; unregister_netdev(netdev); + txgbe_remove_phy((struct txgbe *)wx->priv); + pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c new file mode 100644 index 000000000000..86d5e0647d5e --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ + +#include +#include + +#include "../libwx/wx_type.h" +#include "txgbe_type.h" +#include "txgbe_phy.h" + +static int txgbe_swnodes_register(struct txgbe *txgbe) +{ + struct txgbe_nodes *nodes = &txgbe->nodes; + struct pci_dev *pdev = txgbe->wx->pdev; + struct software_node *swnodes; + u32 id; + + id = (pdev->bus->number << 8) | pdev->devfn; + + snprintf(nodes->gpio_name, sizeof(nodes->gpio_name), "txgbe_gpio-%x", id); + snprintf(nodes->i2c_name, sizeof(nodes->i2c_name), "txgbe_i2c-%x", id); + snprintf(nodes->sfp_name, sizeof(nodes->sfp_name), "txgbe_sfp-%x", id); + snprintf(nodes->phylink_name, sizeof(nodes->phylink_name), "txgbe_phylink-%x", id); + + swnodes = nodes->swnodes; + + /* GPIO 0: tx fault + * GPIO 1: tx disable + * GPIO 2: sfp module absent + * GPIO 3: rx signal lost + * GPIO 4: rate select, 1G(0) 10G(1) + * GPIO 5: rate select, 1G(0) 10G(1) + */ + nodes->gpio_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default"); + swnodes[SWNODE_GPIO] = NODE_PROP(nodes->gpio_name, nodes->gpio_props); + nodes->gpio0_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 0, GPIO_ACTIVE_HIGH); + nodes->gpio1_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 1, GPIO_ACTIVE_HIGH); + nodes->gpio2_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 2, GPIO_ACTIVE_LOW); + nodes->gpio3_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 3, GPIO_ACTIVE_HIGH); + nodes->gpio4_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 4, GPIO_ACTIVE_HIGH); + nodes->gpio5_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_GPIO], 5, GPIO_ACTIVE_HIGH); + + nodes->i2c_props[0] = PROPERTY_ENTRY_STRING("pinctrl-names", "default"); + swnodes[SWNODE_I2C] = NODE_PROP(nodes->i2c_name, nodes->i2c_props); + nodes->i2c_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_I2C]); + + nodes->sfp_props[0] = PROPERTY_ENTRY_STRING("compatible", "sff,sfp"); + nodes->sfp_props[1] = PROPERTY_ENTRY_REF_ARRAY("i2c-bus", nodes->i2c_ref); + nodes->sfp_props[2] = PROPERTY_ENTRY_REF_ARRAY("tx-fault-gpios", nodes->gpio0_ref); + nodes->sfp_props[3] = PROPERTY_ENTRY_REF_ARRAY("tx-disable-gpios", nodes->gpio1_ref); + nodes->sfp_props[4] = PROPERTY_ENTRY_REF_ARRAY("mod-def0-gpios", nodes->gpio2_ref); + nodes->sfp_props[5] = PROPERTY_ENTRY_REF_ARRAY("los-gpios", nodes->gpio3_ref); + nodes->sfp_props[6] = PROPERTY_ENTRY_REF_ARRAY("rate-select1-gpios", nodes->gpio4_ref); + nodes->sfp_props[7] = PROPERTY_ENTRY_REF_ARRAY("rate-select0-gpios", nodes->gpio5_ref); + swnodes[SWNODE_SFP] = NODE_PROP(nodes->sfp_name, nodes->sfp_props); + nodes->sfp_ref[0] = SOFTWARE_NODE_REFERENCE(&swnodes[SWNODE_SFP]); + + nodes->phylink_props[0] = PROPERTY_ENTRY_STRING("managed", "in-band-status"); + nodes->phylink_props[1] = PROPERTY_ENTRY_REF_ARRAY("sfp", nodes->sfp_ref); + swnodes[SWNODE_PHYLINK] = NODE_PROP(nodes->phylink_name, nodes->phylink_props); + + nodes->group[SWNODE_GPIO] = &swnodes[SWNODE_GPIO]; + nodes->group[SWNODE_I2C] = &swnodes[SWNODE_I2C]; + nodes->group[SWNODE_SFP] = &swnodes[SWNODE_SFP]; + nodes->group[SWNODE_PHYLINK] = &swnodes[SWNODE_PHYLINK]; + + return software_node_register_node_group(nodes->group); +} + +int txgbe_init_phy(struct txgbe *txgbe) +{ + int ret; + + ret = txgbe_swnodes_register(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to register software nodes\n"); + return ret; + } + + return 0; +} + +void txgbe_remove_phy(struct txgbe *txgbe) +{ + software_node_unregister_node_group(txgbe->nodes.group); +} diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h new file mode 100644 index 000000000000..1ab592124986 --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ + +#ifndef _TXGBE_PHY_H_ +#define _TXGBE_PHY_H_ + +int txgbe_init_phy(struct txgbe *txgbe); +void txgbe_remove_phy(struct txgbe *txgbe); + +#endif /* _TXGBE_NODE_H_ */ diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 63a1c733718d..d30684378f4e 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -4,6 +4,8 @@ #ifndef _TXGBE_TYPE_H_ #define _TXGBE_TYPE_H_ +#include + /* Device IDs */ #define TXGBE_DEV_ID_SP1000 0x1001 #define TXGBE_DEV_ID_WX1820 0x2001 @@ -99,4 +101,44 @@ extern char txgbe_driver_name[]; +#define NODE_PROP(_NAME, _PROP) \ + (const struct software_node) { \ + .name = _NAME, \ + .properties = _PROP, \ + } + +enum txgbe_swnodes { + SWNODE_GPIO = 0, + SWNODE_I2C, + SWNODE_SFP, + SWNODE_PHYLINK, + SWNODE_MAX +}; + +struct txgbe_nodes { + char gpio_name[32]; + char i2c_name[32]; + char sfp_name[32]; + char phylink_name[32]; + struct property_entry gpio_props[1]; + struct property_entry i2c_props[1]; + struct property_entry sfp_props[8]; + struct property_entry phylink_props[2]; + struct software_node_ref_args i2c_ref[1]; + struct software_node_ref_args gpio0_ref[1]; + struct software_node_ref_args gpio1_ref[1]; + struct software_node_ref_args gpio2_ref[1]; + struct software_node_ref_args gpio3_ref[1]; + struct software_node_ref_args gpio4_ref[1]; + struct software_node_ref_args gpio5_ref[1]; + struct software_node_ref_args sfp_ref[1]; + struct software_node swnodes[SWNODE_MAX]; + const struct software_node *group[SWNODE_MAX + 1]; +}; + +struct txgbe { + struct wx *wx; + struct txgbe_nodes nodes; +}; + #endif /* _TXGBE_TYPE_H_ */ 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: 13207253 X-Patchwork-Delegate: kuba@kernel.org 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 AFC7DC77B79 for ; Tue, 11 Apr 2023 09:29:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229774AbjDKJ2w (ORCPT ); Tue, 11 Apr 2023 05:28:52 -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: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@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:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 13207256 X-Patchwork-Delegate: kuba@kernel.org 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 100D3C77B75 for ; Tue, 11 Apr 2023 09:31:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229825AbjDKJa3 (ORCPT ); Tue, 11 Apr 2023 05:30:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:49868 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230086AbjDKJaY (ORCPT ); Tue, 11 Apr 2023 05:30:24 -0400 Received: from smtpbgau1.qq.com (smtpbgau1.qq.com [54.206.16.166]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8F129272B; Tue, 11 Apr 2023 02:30:10 -0700 (PDT) X-QQ-mid: bizesmtp91t1681205301txy7fiff Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 11 Apr 2023 17:28:20 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000000A0000000 X-QQ-FEAT: q+yjhizk/eKRQYhLfYqTfb9ijkz37drwdg6S2J/VgfatOfFqAX/vIymqIPSDO pPqYRPLMf9n1vmk9j704XMlbNjzaHOoXHQOfMbHU3d4skhLGeNgkIeC1Lv4ZBoUNnK6kWU5 5HysShCZp3UNV5z+f+GybhTbuiWLLZVQI5h0tTi8/EDqCOSDhizIJE5P80MZT8su1eFDCGg kD0sImh4OnuaN8/gefsG3C3KQFNHkqxLkvRyRR2KENqyJhIWm3e2sG4Q109bG4utBvNyZWe M8KVBghWk0jJ6GDdu1zM5Uh/ftJksGJsN0JHslFJdtyaq4/YlmlXXb937/FBKe2J18PS9AB Frkpv321lVtdZAHdZ6kYSL3plAaFh5DaCVoYxnS5TANzwJvpOq6s/hxGAUEOceWV4kmQS8c 0JibgCbQ61g= X-QQ-GoodBg: 2 X-BIZMAIL-ID: 15729466026710604010 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 3/6] net: txgbe: Add SFP module identify Date: Tue, 11 Apr 2023 17:27:22 +0800 Message-Id: <20230411092725.104992-4-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: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Register SFP platform device to get modules information. Signed-off-by: Jiawen Wu Reviewed-by: Andrew Lunn --- drivers/net/ethernet/wangxun/Kconfig | 1 + .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 28 +++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 1 + 3 files changed, 30 insertions(+) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index 8cbf0dd48a2c..c5b62918db78 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -42,6 +42,7 @@ config TXGBE depends on PCI select LIBWX select I2C + select SFP 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 2721da1625e0..dd5ecfad56c1 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ +#include #include #include #include @@ -206,6 +207,25 @@ static int txgbe_i2c_adapter_add(struct txgbe *txgbe) return 0; } +static int txgbe_sfp_register(struct txgbe *txgbe) +{ + struct pci_dev *pdev = txgbe->wx->pdev; + struct platform_device_info info = {}; + struct platform_device *sfp_dev; + + info.parent = &pdev->dev; + info.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_SFP]); + info.name = "sfp"; + info.id = (pdev->bus->number << 8) | pdev->devfn; + sfp_dev = platform_device_register_full(&info); + if (IS_ERR(sfp_dev)) + return PTR_ERR(sfp_dev); + + txgbe->sfp_dev = sfp_dev; + + return 0; +} + int txgbe_init_phy(struct txgbe *txgbe) { int ret; @@ -222,6 +242,12 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err; } + ret = txgbe_sfp_register(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to register sfp\n"); + goto err; + } + return 0; err: @@ -232,6 +258,8 @@ int txgbe_init_phy(struct txgbe *txgbe) void txgbe_remove_phy(struct txgbe *txgbe) { + if (txgbe->sfp_dev) + platform_device_unregister(txgbe->sfp_dev); if (txgbe->i2c_adap) i2c_del_adapter(txgbe->i2c_adap); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index 6c02af196157..a7d6f47cbe05 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -162,6 +162,7 @@ struct txgbe { struct wx *wx; struct txgbe_nodes nodes; struct i2c_adapter *i2c_adap; + struct platform_device *sfp_dev; }; #endif /* _TXGBE_TYPE_H_ */ From patchwork Tue Apr 11 09:27:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 13207258 X-Patchwork-Delegate: kuba@kernel.org 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 C0B57C77B72 for ; Tue, 11 Apr 2023 09:32:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229932AbjDKJcc (ORCPT ); Tue, 11 Apr 2023 05:32:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51614 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229876AbjDKJcW (ORCPT ); Tue, 11 Apr 2023 05:32:22 -0400 Received: from smtpbguseast3.qq.com (smtpbguseast3.qq.com [54.243.244.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D90132D6A; Tue, 11 Apr 2023 02:32:19 -0700 (PDT) X-QQ-mid: bizesmtp91t1681205304t0l96ac4 Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 11 Apr 2023 17:28:23 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000000A0000000 X-QQ-FEAT: 0laiA9+vjAC8zSEHFWjRRWd70XdQNF5FynXI1t/jobIE1GQOC+uFa7OWMLCFX m5y1Y06e9GwSDJxpCElKtiYBSkTab9k7Gbv3/KkP9xCDzRFsRukjr3VoV+apcaNHbYt5mm0 wi1WQuxJFdmbgYRghR53RMM9tZxjYpAv1IYUzKiUQAD7BGYGTDfoIFlaYJXT6CJBNeWzl5u svJY8WxjEAmG22Fz7b0rYc5kDBiu01h06iuoWZGPbRnsfhsBECpUBXGNj+nBG3L7RpS3K05 I4seICuBfFwGcRBLc07BBadXGwfbNLum09+Bjr9Ckc4KsQkNmbOOVtMljZstHKuJGNGNQNk chDYIcuPBr2mqM0fOvAgco9FfvxGn3M5U2CQfiUU1gfdFzr08Qk8LKqTXBlE+Xv55xTO21B gfYEMOK9f3NnRDiAuhtsHQ== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 8522345960086558971 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 4/6] net: txgbe: Support GPIO to SFP socket Date: Tue, 11 Apr 2023 17:27:23 +0800 Message-Id: <20230411092725.104992-5-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: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Register GPIO chip and handle GPIO IRQ for SFP socket. Signed-off-by: Jiawen Wu --- drivers/net/ethernet/wangxun/Kconfig | 2 + drivers/net/ethernet/wangxun/libwx/wx_lib.c | 3 +- drivers/net/ethernet/wangxun/libwx/wx_type.h | 2 + .../net/ethernet/wangxun/txgbe/txgbe_main.c | 20 +- .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 227 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 27 +++ 6 files changed, 262 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index c5b62918db78..d9cccdad8a53 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -40,6 +40,8 @@ config NGBE config TXGBE tristate "Wangxun(R) 10GbE PCI Express adapters support" depends on PCI + select GPIOLIB_IRQCHIP + select GPIOLIB select LIBWX select I2C select SFP diff --git a/drivers/net/ethernet/wangxun/libwx/wx_lib.c b/drivers/net/ethernet/wangxun/libwx/wx_lib.c index eb89a274083e..dff0d573ee33 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_lib.c +++ b/drivers/net/ethernet/wangxun/libwx/wx_lib.c @@ -1348,7 +1348,8 @@ void wx_free_irq(struct wx *wx) free_irq(entry->vector, q_vector); } - free_irq(wx->msix_entries[vector].vector, wx); + if (wx->mac.type == wx_mac_em) + free_irq(wx->msix_entries[vector].vector, wx); } EXPORT_SYMBOL(wx_free_irq); diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h index 97bce855bc60..d151d6f79022 100644 --- a/drivers/net/ethernet/wangxun/libwx/wx_type.h +++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h @@ -79,7 +79,9 @@ #define WX_GPIO_INTMASK 0x14834 #define WX_GPIO_INTTYPE_LEVEL 0x14838 #define WX_GPIO_POLARITY 0x1483C +#define WX_GPIO_INTSTATUS 0x14844 #define WX_GPIO_EOI 0x1484C +#define WX_GPIO_EXT 0x14850 /*********************** Transmit DMA registers **************************/ /* transmit global control */ diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 5a5e7620e9f8..d8108ab30818 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -82,6 +82,8 @@ static int txgbe_enumerate_functions(struct wx *wx) **/ static void txgbe_irq_enable(struct wx *wx, bool queues) { + wr32(wx, WX_PX_MISC_IEN, TXGBE_PX_MISC_IEN_MASK); + /* unmask interrupt */ wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); if (queues) @@ -129,17 +131,6 @@ static irqreturn_t txgbe_intr(int __always_unused irq, void *data) return IRQ_HANDLED; } -static irqreturn_t txgbe_msix_other(int __always_unused irq, void *data) -{ - struct wx *wx = data; - - /* re-enable the original interrupt state */ - if (netif_running(wx->netdev)) - txgbe_irq_enable(wx, false); - - return IRQ_HANDLED; -} - /** * txgbe_request_msix_irqs - Initialize MSI-X interrupts * @wx: board private structure @@ -171,13 +162,6 @@ static int txgbe_request_msix_irqs(struct wx *wx) } } - err = request_irq(wx->msix_entries[vector].vector, - txgbe_msix_other, 0, netdev->name, wx); - if (err) { - wx_err(wx, "request_irq for msix_other failed: %d\n", err); - goto free_queue_irqs; - } - return 0; free_queue_irqs: diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c index dd5ecfad56c1..42e66db6e9ff 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -2,6 +2,9 @@ /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */ #include +#include +#include +#include #include #include #include @@ -207,6 +210,224 @@ static int txgbe_i2c_adapter_add(struct txgbe *txgbe) return 0; } +static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(chip); + struct txgbe *txgbe; + int val; + + val = rd32m(wx, WX_GPIO_EXT, BIT(offset)); + + txgbe = (struct txgbe *)wx->priv; + txgbe->gpio_orig &= ~BIT(offset); + txgbe->gpio_orig |= val; + + return !!(val & BIT(offset)); +} + +static int txgbe_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(chip); + u32 val; + + val = rd32(wx, WX_GPIO_DDR); + if (BIT(offset) & val) + return GPIO_LINE_DIRECTION_OUT; + + return GPIO_LINE_DIRECTION_IN; +} + +static int txgbe_gpio_direction_in(struct gpio_chip *chip, unsigned int offset) +{ + struct wx *wx = gpiochip_get_data(chip); + + wr32m(wx, WX_GPIO_DDR, BIT(offset), 0); + + return 0; +} + +static int txgbe_gpio_direction_out(struct gpio_chip *chip, unsigned int offset, + int val) +{ + struct wx *wx = gpiochip_get_data(chip); + u32 mask; + + mask = BIT(offset) | BIT(offset - 1); + if (val) + wr32m(wx, WX_GPIO_DR, mask, mask); + else + wr32m(wx, WX_GPIO_DR, mask, 0); + + wr32m(wx, WX_GPIO_DDR, BIT(offset), BIT(offset)); + + return 0; +} + +static void txgbe_gpio_irq_ack(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + + wr32(wx, WX_GPIO_EOI, BIT(hwirq)); +} + +static void txgbe_gpio_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + + gpiochip_disable_irq(gc, hwirq); + + wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), BIT(hwirq)); +} + +static void txgbe_gpio_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + + gpiochip_enable_irq(gc, hwirq); + + wr32m(wx, WX_GPIO_INTMASK, BIT(hwirq), 0); +} + +static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + irq_hw_number_t hwirq = irqd_to_hwirq(d); + struct wx *wx = gpiochip_get_data(gc); + u32 level, polarity; + + level = rd32(wx, WX_GPIO_INTTYPE_LEVEL); + polarity = rd32(wx, WX_GPIO_POLARITY); + + switch (type) { + case IRQ_TYPE_EDGE_BOTH: + level |= BIT(hwirq); + break; + case IRQ_TYPE_EDGE_RISING: + level |= BIT(hwirq); + polarity |= BIT(hwirq); + break; + case IRQ_TYPE_EDGE_FALLING: + level |= BIT(hwirq); + polarity &= ~BIT(hwirq); + break; + case IRQ_TYPE_LEVEL_HIGH: + level &= ~BIT(hwirq); + polarity |= BIT(hwirq); + break; + case IRQ_TYPE_LEVEL_LOW: + level &= ~BIT(hwirq); + polarity &= ~BIT(hwirq); + break; + } + + if (type & IRQ_TYPE_LEVEL_MASK) + irq_set_handler_locked(d, handle_level_irq); + else if (type & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(d, handle_edge_irq); + + wr32m(wx, WX_GPIO_INTEN, BIT(hwirq), BIT(hwirq)); + wr32(wx, WX_GPIO_INTTYPE_LEVEL, level); + if (type != IRQ_TYPE_EDGE_BOTH) + wr32(wx, WX_GPIO_POLARITY, polarity); + + return 0; +} + +static const struct irq_chip txgbe_gpio_irq_chip = { + .name = "txgbe_gpio_irq", + .irq_ack = txgbe_gpio_irq_ack, + .irq_mask = txgbe_gpio_irq_mask, + .irq_unmask = txgbe_gpio_irq_unmask, + .irq_set_type = txgbe_gpio_set_type, + .flags = IRQCHIP_IMMUTABLE, + GPIOCHIP_IRQ_RESOURCE_HELPERS, +}; + +static void txgbe_irq_handler(struct irq_desc *desc) +{ + struct irq_chip *chip = irq_desc_get_chip(desc); + struct wx *wx = irq_desc_get_handler_data(desc); + struct txgbe *txgbe = (struct txgbe *)wx->priv; + struct gpio_chip *gc = txgbe->gpio; + irq_hw_number_t hwirq; + unsigned long gpioirq; + u32 gpio; + + chained_irq_enter(chip, desc); + + gpioirq = rd32(wx, WX_GPIO_INTSTATUS); + + /* workaround for hysteretic gpio interrupts */ + gpio = rd32(wx, WX_GPIO_EXT); + if (!gpioirq) + gpioirq = txgbe->gpio_orig ^ gpio; + + for_each_set_bit(hwirq, &gpioirq, gc->ngpio) + generic_handle_domain_irq(gc->irq.domain, hwirq); + + chained_irq_exit(chip, desc); + + /* unmask interrupt */ + if (netif_running(wx->netdev)) + wx_intr_enable(wx, TXGBE_INTR_MISC(wx)); +} + +static int txgbe_gpio_init(struct txgbe *txgbe) +{ + struct gpio_irq_chip *girq; + struct wx *wx = txgbe->wx; + struct pci_dev *pdev; + struct gpio_chip *gc; + int ret; + + pdev = wx->pdev; + txgbe->gpio_orig = 0; + + gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); + if (!gc) + return -ENOMEM; + + gc->label = devm_kasprintf(&pdev->dev, GFP_KERNEL, "txgbe_gpio-%x", + (pdev->bus->number << 8) | pdev->devfn); + gc->base = -1; + gc->ngpio = 6; + gc->owner = THIS_MODULE; + gc->parent = &pdev->dev; + gc->fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_GPIO]); + gc->get = txgbe_gpio_get; + gc->get_direction = txgbe_gpio_get_direction; + gc->direction_input = txgbe_gpio_direction_in; + gc->direction_output = txgbe_gpio_direction_out; + gc->can_sleep = false; + + girq = &gc->irq; + gpio_irq_chip_set_chip(girq, &txgbe_gpio_irq_chip); + girq->parent_handler = txgbe_irq_handler; + girq->parent_handler_data = wx; + girq->num_parents = 1; + girq->parents = devm_kcalloc(&pdev->dev, 1, sizeof(*girq->parents), + GFP_KERNEL); + if (!girq->parents) + return -ENOMEM; + girq->parents[0] = wx->msix_entries[wx->num_q_vectors].vector; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_bad_irq; + + ret = devm_gpiochip_add_data(&pdev->dev, gc, wx); + if (ret) + return ret; + + txgbe->gpio = gc; + + return 0; +} + static int txgbe_sfp_register(struct txgbe *txgbe) { struct pci_dev *pdev = txgbe->wx->pdev; @@ -242,6 +463,12 @@ int txgbe_init_phy(struct txgbe *txgbe) goto err; } + ret = txgbe_gpio_init(txgbe); + if (ret) { + wx_err(txgbe->wx, "failed to init gpio\n"); + goto err; + } + ret = txgbe_sfp_register(txgbe); if (ret) { wx_err(txgbe->wx, "failed to register sfp\n"); diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index a7d6f47cbe05..58b0054ae59c 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -55,6 +55,31 @@ #define TXGBE_TS_CTL 0x10300 #define TXGBE_TS_CTL_EVAL_MD BIT(31) +/* GPIO register bit */ +#define TXGBE_GPIOBIT_0 BIT(0) /* I:tx fault */ +#define TXGBE_GPIOBIT_1 BIT(1) /* O:tx disabled */ +#define TXGBE_GPIOBIT_2 BIT(2) /* I:sfp module absent */ +#define TXGBE_GPIOBIT_3 BIT(3) /* I:rx signal lost */ +#define TXGBE_GPIOBIT_4 BIT(4) /* O:rate select, 1G(0) 10G(1) */ +#define TXGBE_GPIOBIT_5 BIT(5) /* O:rate select, 1G(0) 10G(1) */ + +/* Extended Interrupt Enable Set */ +#define TXGBE_PX_MISC_ETH_LKDN BIT(8) +#define TXGBE_PX_MISC_DEV_RST BIT(10) +#define TXGBE_PX_MISC_ETH_EVENT BIT(17) +#define TXGBE_PX_MISC_ETH_LK BIT(18) +#define TXGBE_PX_MISC_ETH_AN BIT(19) +#define TXGBE_PX_MISC_INT_ERR BIT(20) +#define TXGBE_PX_MISC_GPIO BIT(26) +#define TXGBE_PX_MISC_IEN_MASK ( \ + TXGBE_PX_MISC_ETH_LKDN | \ + TXGBE_PX_MISC_DEV_RST | \ + TXGBE_PX_MISC_ETH_EVENT | \ + TXGBE_PX_MISC_ETH_LK | \ + TXGBE_PX_MISC_ETH_AN | \ + TXGBE_PX_MISC_INT_ERR | \ + TXGBE_PX_MISC_GPIO) + /* I2C registers */ #define TXGBE_I2C_CON 0x14900 /* I2C Control */ #define TXGBE_I2C_CON_SLAVE_DISABLE BIT(6) @@ -162,7 +187,9 @@ struct txgbe { struct wx *wx; struct txgbe_nodes nodes; struct i2c_adapter *i2c_adap; + struct gpio_chip *gpio; struct platform_device *sfp_dev; + u32 gpio_orig; }; #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: 13207257 X-Patchwork-Delegate: kuba@kernel.org 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 E12ECC77B72 for ; Tue, 11 Apr 2023 09:31:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229802AbjDKJbA (ORCPT ); Tue, 11 Apr 2023 05:31:00 -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: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@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: 13207255 X-Patchwork-Delegate: kuba@kernel.org 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 EA9B5C77B74 for ; Tue, 11 Apr 2023 09:29:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229778AbjDKJ3Y (ORCPT ); Tue, 11 Apr 2023 05:29:24 -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: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@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;