From patchwork Mon Apr 3 06:45: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: 13197689 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 B9DE3C761A6 for ; Mon, 3 Apr 2023 06:48:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231526AbjDCGsC (ORCPT ); Mon, 3 Apr 2023 02:48:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51114 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231470AbjDCGsA (ORCPT ); Mon, 3 Apr 2023 02:48:00 -0400 Received: from smtpbgbr2.qq.com (smtpbgbr2.qq.com [54.207.22.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 99E6810E for ; Sun, 2 Apr 2023 23:47:56 -0700 (PDT) X-QQ-mid: bizesmtp63t1680504424tuv1i5w4 Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 03 Apr 2023 14:47:03 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000B00A0000000 X-QQ-FEAT: LGwoLArZsiWGU1UG3FSXpXBtqsLgQPdwLxPs28KYoHUaOYq03n81j3q2d4X6c 367pIpWyevV0jzeImUT5KY8olCd0DfVgU/57DBOqY0uaLpmPfG/kJNNgNvGxJuDSU18w5Nv VX/Am5yc/uT1m4jOcjKvRepMMe+bit4DpFdRl9pcJuSDIdVYpUg3aRWM978H0OfPOHIUv4B RnAKPDt14ZJQrqI/suCP3O6K6B6aEoKZIqwSyKb/r828+r9WAeRdrN7i7RAEbrgHQIk9hpD Ivllue5CqSBsqJ1NUfEyy3t7SeMq3nOPCpM550ISvcZV180Yrp8UzdCYu/EXAmQvo60cUBj MnnaqXrQPtDGhGnN5zqTbkyi7Ms28eprrpvU7juA9SGAr+Ehor4wwFhXe8lCGb6E9QVz1eX H8PHdkJVYHvaPSy1FZ5q+w== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 17123510608791016634 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next 1/6] net: txgbe: Add software nodes to support phylink Date: Mon, 3 Apr 2023 14:45:23 +0800 Message-Id: <20230403064528.343866-2-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230403064528.343866-1-jiawenwu@trustnetic.com> References: <20230403064528.343866-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 --- 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 | 79 +++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_phy.h | 10 +++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 42 ++++++++++ 6 files changed, 151 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 2bec5b1bc196..072aa2bd3fdc 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 843a88bc416f..319d56720c06 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"; @@ -512,6 +513,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; @@ -662,10 +664,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); @@ -693,6 +706,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); @@ -723,6 +738,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..163acb7e515e --- /dev/null +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c @@ -0,0 +1,79 @@ +// 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; + + 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 Mon Apr 3 06:45: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: 13197690 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 0FEC9C76196 for ; Mon, 3 Apr 2023 06:48:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230433AbjDCGsG (ORCPT ); Mon, 3 Apr 2023 02:48:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51142 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231494AbjDCGsB (ORCPT ); Mon, 3 Apr 2023 02:48:01 -0400 Received: from smtpbgbr2.qq.com (smtpbgbr2.qq.com [54.207.22.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 33C721FED for ; Sun, 2 Apr 2023 23:47:57 -0700 (PDT) X-QQ-mid: bizesmtp63t1680504427te16rxw1 Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 03 Apr 2023 14:47:06 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000B00A0000000 X-QQ-FEAT: KSpVqVeA+UWmIaeNZPWu+RaAv/tcGCS0S2CjmLQIjyPa4hfWjzrAVjsZNeyrd byfAIlmZek/agQFAYUwPMTWICAKFnPEO/oY0x6fvKaytdDNbe2QqX7AW514flLYE8Vn46Y4 DBS/Om10g9E0H8F/apQ8N922V5M1wI8hqEZGJGIch6jVvGdowitrynQT9vFb6tW2Qk3UGV1 HtOCl4IMzp5N7alc1XZ18zUPG8KihaHl/1oor/8am7kZsbfy+9fM6sLp8MEl7f15s0s9Lol Ov3CqroqTSgujl2/6l4Asj/wVfcrWrDT4fZjS5jChiiBbS5Q00rAO3cVYmeV9ypqSqz/f+l jmUmmSAxbGfDlvfYX0Rz3GpSf7ZwmxFd/YpL6g0d/UB6auSDcDRwUWlUBU/v1yCZvulVGfU gR2D0qSRpR4LclI/h+TVHQ== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 858744205473956203 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next 2/6] net: txgbe: Implement I2C bus master driver Date: Mon, 3 Apr 2023 14:45:24 +0800 Message-Id: <20230403064528.343866-3-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230403064528.343866-1-jiawenwu@trustnetic.com> References: <20230403064528.343866-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 I2C bus is integrated in Wangxun 10Gb ethernet chip. Implement I2C bus driver to receive I2C messages. Signed-off-by: Jiawen Wu --- drivers/net/ethernet/wangxun/Kconfig | 1 + .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 141 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 26 ++++ 3 files changed, 168 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 163acb7e515e..f8a4b211f4e8 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" @@ -60,6 +63,130 @@ 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)); + /* Default addr is 0xA0 ,bit 0 is configure for read/write! */ + 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_read_i2c_bytes(struct wx *wx, u8 addr, u16 len, u8 *buf) +{ + int err, i; + u16 val; + + for (i = 0; i < len; i++) { + /* wait tx empty */ + err = read_poll_timeout(rd32, val, + (val & TXGBE_I2C_INTR_STAT_TEMP) == + TXGBE_I2C_INTR_STAT_TEMP, + 100, 1000, false, wx, + TXGBE_I2C_RAW_INTR_STAT); + if (err != 0) + return err; + + /* read data */ + wr32(wx, TXGBE_I2C_DATA_CMD, (addr + i) | TXGBE_I2C_DATA_CMD_STOP); + wr32(wx, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_READ); + + /* wait for read complete */ + err = read_poll_timeout(rd32, val, + (val & TXGBE_I2C_INTR_STAT_RFUL) == + TXGBE_I2C_INTR_STAT_RFUL, + 100, 1000, false, wx, + TXGBE_I2C_RAW_INTR_STAT); + if (err != 0) + return err; + + buf[i] = 0xFF & rd32(wx, TXGBE_I2C_DATA_CMD); + } + + 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; + bool read = false; + int i, ret; + u8 *buf; + u16 len; + + txgbe_i2c_start(wx, msg[0].addr); + + for (i = 0; i < num_msgs; i++) { + if (msg[i].flags & I2C_M_RD) { + read = true; + len = msg[i].len; + buf = msg[i].buf; + } + } + + if (!read) { + wx_err(wx, "I2C write not supported\n"); + return num_msgs; + } + + ret = txgbe_read_i2c_bytes(wx, *dev_addr, len, buf); + if (!ret) + ret = num_msgs; + + return ret; +} + +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; @@ -70,10 +197,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..de488609f713 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) +/* 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) | TXGBE_I2C_DATA_CMD_STOP) +#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 + +#define TXGBE_I2C_SLAVE_ADDR (0xA0 >> 1) +#define TXGBE_I2C_EEPROM_DEV_ADDR 0xA0 + /* Part Number String Length */ #define TXGBE_PBANUM_LENGTH 32 @@ -139,6 +164,7 @@ struct txgbe_nodes { struct txgbe { struct wx *wx; struct txgbe_nodes nodes; + struct i2c_adapter *i2c_adap; }; #endif /* _TXGBE_TYPE_H_ */ From patchwork Mon Apr 3 06:45: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: 13197692 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 E9EE6C761A6 for ; Mon, 3 Apr 2023 06:48:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231552AbjDCGsP (ORCPT ); Mon, 3 Apr 2023 02:48:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51184 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231510AbjDCGsD (ORCPT ); Mon, 3 Apr 2023 02:48:03 -0400 Received: from smtpbgbr2.qq.com (smtpbgbr2.qq.com [54.207.22.56]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE2F82727 for ; Sun, 2 Apr 2023 23:47:58 -0700 (PDT) X-QQ-mid: bizesmtp63t1680504430twv508bj Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 03 Apr 2023 14:47:09 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000B00A0000000 X-QQ-FEAT: znfcQSa1hKZK20aq+z/+RddqGsJFHBxejDwrkK+reTZkVpIja3/52cGPw0up4 /7JXO0W4ZeQgXHhUZjJFR3XMYbWVbXuFt8dr0MUd3GFXMBY3Ucf7xSRTLPRGq1XG+RpJcns pLq31nr3wflACHXPtx0oS79WPzkZsMosWxgiQVHqRS064Cfw/KKQ8kw6DPbsPZS7quk55KY iZ1qRkBwTRXX1VZva/AYPx+oIqCHTj33Q0tEvNwDjW9PjbnjxJ60GyvmQLKoD+e49acRG5p R6z7aU8pWqXXdGH4/V0fHcOydsswCubxpAB6qyA/aBIp+Cg7w+cRYgMzpBK8uEEgAlfSb09 VeQwn/874Zm/M1G1WJHia8XuPiy62/ArE9/NcdoYkFChxFSyS4WHv8WjHOKdk2e+bzH6apr O39OWFwF6CAI/zlttKhrzg== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 4876250889537453862 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next 3/6] net: txgbe: Add SFP module identify Date: Mon, 3 Apr 2023 14:45:25 +0800 Message-Id: <20230403064528.343866-4-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230403064528.343866-1-jiawenwu@trustnetic.com> References: <20230403064528.343866-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 --- .../device_drivers/ethernet/wangxun/txgbe.rst | 47 +++++++++++++++++++ drivers/net/ethernet/wangxun/Kconfig | 1 + .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 29 ++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 1 + 4 files changed, 78 insertions(+) diff --git a/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst b/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst index d052ef40fe36..9eb05a2ef110 100644 --- a/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst +++ b/Documentation/networking/device_drivers/ethernet/wangxun/txgbe.rst @@ -11,9 +11,56 @@ Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. Contents ======== +- Identifying Adapter - Support +Identifying Adapter +=================== +The driver is compatible with WangXun Sapphire Dual ports Ethernet Adapters. + +SFP+ Devices with Pluggable Optics +---------------------------------- +The following is a list of 3rd party SFP+ modules that have been tested and verified. + ++----------+----------------------+----------------------+ +| Supplier | Type | Part Numbers | ++==========+======================+======================+ +| ACCELINK | SFP+ | RTXM228-551 | ++----------+----------------------+----------------------+ +| Avago | SFP+ | SFBR-7701SDZ | ++----------+----------------------+----------------------+ +| BOYANG | SFP+ | OMXD30000 | ++----------+----------------------+----------------------+ +| F-tone | SFP+ | FTCS-851X-02D | ++----------+----------------------+----------------------+ +| FS | SFP+ | SFP-10GSR-85 | ++----------+----------------------+----------------------+ +| Finisar | SFP+ | FTLX8574D3BCL | ++----------+----------------------+----------------------+ +| Hisense | SFP+ | LTF8502-BC+ | ++----------+----------------------+----------------------+ +| HGTECH | SFP+ | MTRS-01X11-G | ++----------+----------------------+----------------------+ +| HP | SFP+ | SR SFP+ 456096-001 | ++----------+----------------------+----------------------+ +| Huawei | SFP+ | AFBR-709SMZ | ++----------+----------------------+----------------------+ +| Intel | SFP+ | FTLX8571D3BCV-IT | ++----------+----------------------+----------------------+ +| JDSU | SFP+ | PLRXPL-SC-S43 | ++----------+----------------------+----------------------+ +| SONT | SFP+ | XP-8G10-01 | ++----------+----------------------+----------------------+ +| Trixon | SFP+ | TPS-TGM3-85DCR | ++----------+----------------------+----------------------+ + +Laser turns off for SFP+ when ifconfig ethX down +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"ifconfig ethX down" turns off the laser for SFP+ fiber adapters. +"ifconfig ethX up" turns on the laser. + + Support ======= If you got any problem, contact Wangxun support team via nic-support@net-swift.com 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 f8a4b211f4e8..dac9dfd001f0 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 @@ -187,6 +188,26 @@ 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; + + memset(&info, 0, sizeof(info)); + 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; @@ -203,6 +224,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: @@ -213,6 +240,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 de488609f713..75a4e7b8cc51 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h @@ -165,6 +165,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 Mon Apr 3 06:45:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 13197691 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 B6438C761AF for ; Mon, 3 Apr 2023 06:48:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231524AbjDCGsE (ORCPT ); Mon, 3 Apr 2023 02:48:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231486AbjDCGsA (ORCPT ); Mon, 3 Apr 2023 02:48:00 -0400 Received: from smtpbgsg2.qq.com (smtpbgsg2.qq.com [54.254.200.128]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 860241BC5 for ; Sun, 2 Apr 2023 23:47:57 -0700 (PDT) X-QQ-mid: bizesmtp63t1680504433tae6ynrg Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 03 Apr 2023 14:47:12 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000B00A0000000 X-QQ-FEAT: KSpVqVeA+UU2ASOLpqU+n9wCyX8aQcgKbzAIzB5CjsTOjLmXuIduLTk0b9DZN m5Z2h+B5/Be65/0ESkVA0UeLZn9H6BTxajaLPS7CQ2G4+QD9YfFdAZQH1H7tiDAsyLDbQuQ VgryAjhAzgmEd06e5LNTcWDFhEhIqHvqVflFb/4tGiU6owQ7V540rr/zIAvik15LPOZimOO 18kwwYefzMx4RehArWkLNu07oODedV+MrF/eeFYlp1kPZph4/MbLYShBd8qQNWFX1nt/uAT Z2u0+dIblS5NE4oLqKXqEWFXK/7OXHd9+p1Sq1pY2Gce6cXVeQ3nr5PWoToax8LA9y7egB7 0CzD/d2E3Qs1bRDSz85d3KAnIgsRG+zUStDoeRWC3T+Tc7BAWjsbp8yJoFcFhG69NkFk2ct RYR4M1yiqlQfrhQPZNlvQA== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 1725779558253379975 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next 4/6] net: txgbe: Support GPIO to SFP socket Date: Mon, 3 Apr 2023 14:45:26 +0800 Message-Id: <20230403064528.343866-5-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230403064528.343866-1-jiawenwu@trustnetic.com> References: <20230403064528.343866-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 + drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c | 1 + .../net/ethernet/wangxun/txgbe/txgbe_main.c | 22 +- .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 216 ++++++++++++++++++ .../net/ethernet/wangxun/txgbe/txgbe_type.h | 26 +++ 7 files changed, 253 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 072aa2bd3fdc..89bba827edf2 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_hw.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c index ebc46f3be056..b87034e57140 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_hw.c @@ -256,6 +256,7 @@ int txgbe_validate_eeprom_checksum(struct wx *wx, u16 *checksum_val) static void txgbe_reset_misc(struct wx *wx) { wx_reset_misc(wx); + wr32(wx, WX_GPIO_DDR, 0x32); txgbe_init_thermal_sensor_thresh(wx); } diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c index 319d56720c06..caaefc20afb9 100644 --- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c +++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c @@ -82,6 +82,10 @@ static int txgbe_enumerate_functions(struct wx *wx) **/ static void txgbe_irq_enable(struct wx *wx, bool queues) { + wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_0 | TXGBE_GPIOBIT_2 | TXGBE_GPIOBIT_3); + wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_0 | TXGBE_GPIOBIT_2 | TXGBE_GPIOBIT_3); + 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 +133,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 +164,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 dac9dfd001f0..fe51485a9b68 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 @@ -188,6 +191,213 @@ 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); + int val, dir; + + dir = chip->get_direction(chip, offset); + if (dir == GPIO_LINE_DIRECTION_IN) + val = rd32m(wx, WX_GPIO_EXT, BIT(offset)); + else + val = rd32m(wx, WX_GPIO_DR, BIT(offset)); + + 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) +{ + 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; + int dir; + + dir = chip->get_direction(chip, offset); + if (dir == GPIO_LINE_DIRECTION_IN) + return 0; + + mask = BIT(offset) | BIT(offset - 1); + if (val) + wr32m(wx, WX_GPIO_DR, mask, mask); + else + wr32m(wx, WX_GPIO_DR, mask, 0); + + 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); + + 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 val; + + chained_irq_enter(chip, desc); + + val = rd32(wx, WX_GPIO_INTSTATUS); + for_each_set_bit(hwirq, &val, 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; + + 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; @@ -224,6 +434,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 75a4e7b8cc51..ea2b39252edf 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) @@ -165,6 +190,7 @@ struct txgbe { struct wx *wx; struct txgbe_nodes nodes; struct i2c_adapter *i2c_adap; + struct gpio_chip *gpio; struct platform_device *sfp_dev; }; From patchwork Mon Apr 3 06:45:27 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 13197693 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 B9084C76196 for ; Mon, 3 Apr 2023 06:48:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231543AbjDCGsR (ORCPT ); Mon, 3 Apr 2023 02:48:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51232 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231486AbjDCGsF (ORCPT ); Mon, 3 Apr 2023 02:48:05 -0400 Received: from smtpbg156.qq.com (smtpbg156.qq.com [15.184.82.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 824C74206 for ; Sun, 2 Apr 2023 23:48:01 -0700 (PDT) X-QQ-mid: bizesmtp63t1680504436ts163cfa Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 03 Apr 2023 14:47:15 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000B00A0000000 X-QQ-FEAT: jXjag1m6xl62P+H16ZOwvK6Fo047nLvUr41A7ZnWCnawuFiZCaZYdf1a5847x DlJjUOyIQTEUCa1FsAqWok6GzCuWiOhxoLfeIDxxV0j7iqOQtIHJORdzq8EA1gMZinb9G6L rtC/soowTe+7rJNwIDO3iOk1ivOlAjDQ2TZfdaynY0dYbTWHsa9IVzSJSwBYqc4Rc9XxG1w vtWUs5ukzhEpMO6BmgbqBZRd2dckZb4/xaT+IWlOgrsNqdZVoVEcBkj69pEgsTjTGgT4Q6K kQCR1W9Ds7VPD9FfiTYgP10UNQ/poBR6P1TJGBal0XdVmdjKghTb+tlpCWHHtElPiTluEas 6Hykog8xt4YmIzlte83jqQLJGoTigHluLDt7EmijLJWewlEhazsxiIoJ03IUYJLQIH3WeFX Az2dTi3wtdg= X-QQ-GoodBg: 2 X-BIZMAIL-ID: 16965943134361158160 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next 5/6] net: txgbe: Implement phylink pcs Date: Mon, 3 Apr 2023 14:45:27 +0800 Message-Id: <20230403064528.343866-6-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230403064528.343866-1-jiawenwu@trustnetic.com> References: <20230403064528.343866-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 | 371 +++++++++++++++++- .../net/ethernet/wangxun/txgbe/txgbe_type.h | 56 +++ 3 files changed, 423 insertions(+), 5 deletions(-) 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 fe51485a9b68..a00651ba021f 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 @@ -67,6 +69,344 @@ 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 void txgbe_pma_config_10gbr(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_1000bx(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_sgmii_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(2)); + 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 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; + + /* 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_10gbr(txgbe); + break; + case PHY_INTERFACE_MODE_1000BASEX: + txgbe_pma_config_1000bx(txgbe); + txgbe_set_sgmii_an37_ability(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"); + + 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; + + /* For C37 1000BASEX mode */ + if (linkmode_test_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, + state->advertising)) { + /* Reset link state */ + state->link = false; + + /* Poll for link jitter */ + read_poll_timeout(pcs_read, lpa, lpa, + 100, 50000, false, 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; + } + + 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); + int ret; + + ret = pcs_read(txgbe, MDIO_MMD_VEND2, MDIO_CTRL1); + if (ret >= 0) { + ret |= BMCR_ANRESTART; + pcs_write(txgbe, MDIO_MMD_VEND2, MDIO_CTRL1, ret); + } +} + +static const struct phylink_pcs_ops txgbe_pcs_ops = { + .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); @@ -197,10 +537,15 @@ static int txgbe_gpio_get(struct gpio_chip *chip, unsigned int offset) int val, dir; dir = chip->get_direction(chip, offset); - if (dir == GPIO_LINE_DIRECTION_IN) + if (dir == GPIO_LINE_DIRECTION_IN) { + struct txgbe *txgbe = (struct txgbe *)wx->priv; + val = rd32m(wx, WX_GPIO_EXT, BIT(offset)); - else + txgbe->gpio_orig &= ~BIT(offset); + txgbe->gpio_orig |= val; + } else { val = rd32m(wx, WX_GPIO_DR, BIT(offset)); + } return !!(val & BIT(offset)); } @@ -334,12 +679,19 @@ static void txgbe_irq_handler(struct irq_desc *desc) struct txgbe *txgbe = (struct txgbe *)wx->priv; struct gpio_chip *gc = txgbe->gpio; irq_hw_number_t hwirq; - unsigned long val; + unsigned long gpioirq; + u32 gpio; chained_irq_enter(chip, desc); - val = rd32(wx, WX_GPIO_INTSTATUS); - for_each_set_bit(hwirq, &val, gc->ngpio) + 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); @@ -358,6 +710,7 @@ static int txgbe_gpio_init(struct txgbe *txgbe) int ret; pdev = wx->pdev; + txgbe->gpio_orig = 0; gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); if (!gc) @@ -428,6 +781,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); @@ -456,6 +815,8 @@ int txgbe_init_phy(struct txgbe *txgbe) void txgbe_remove_phy(struct txgbe *txgbe) { + if (txgbe->mdiodev) + mdio_device_free(txgbe->mdiodev); 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 ea2b39252edf..d121edadfd09 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 */ @@ -105,6 +108,56 @@ #define TXGBE_I2C_SLAVE_ADDR (0xA0 >> 1) #define TXGBE_I2C_EEPROM_DEV_ADDR 0xA0 +/************************************** 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) +/* 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 @@ -189,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; + u32 gpio_orig; }; #endif /* _TXGBE_TYPE_H_ */ From patchwork Mon Apr 3 06:45:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jiawen Wu X-Patchwork-Id: 13197694 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 44627C761A6 for ; Mon, 3 Apr 2023 06:48:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231486AbjDCGsT (ORCPT ); Mon, 3 Apr 2023 02:48:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:51302 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231534AbjDCGsG (ORCPT ); Mon, 3 Apr 2023 02:48:06 -0400 Received: from smtpbguseast3.qq.com (smtpbguseast3.qq.com [54.243.244.52]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7873A275 for ; Sun, 2 Apr 2023 23:48:03 -0700 (PDT) X-QQ-mid: bizesmtp63t1680504439tbea86j4 Received: from wxdbg.localdomain.com ( [183.129.236.74]) by bizesmtp.qq.com (ESMTP) with id ; Mon, 03 Apr 2023 14:47:18 +0800 (CST) X-QQ-SSF: 01400000000000H0Z000B00A0000000 X-QQ-FEAT: KSpVqVeA+UV/Fv1vBgwtcoGeU1Uamj9oJZ/ksldXmlniiCyOExJoUThw88mzA ZeARFYqKKuUvdiaKHmDNfurYQkfinRArsrZFUpF7B08wiuglV1heCgsOb6KExH2Kv+y4m5p Yh0OnChiMmAf099VCUTeXwlP0fqyvbYUm7mx98Y2fMI7L9a7j94TeuejF8I7Amygz7uD2Gm IvDPlSKjg5jC3KSlAQ7DDJLMK9rcAu2jjdpy5nFtlEfTTn0wRk7kLqipFtFNox4aAn6vI/X NoYShJhNw/QZ56UK6h0c/exk5fNnbZ5JT+0Kaw9PZrcbjU0y1u9Sie/v76b0wew3Z1wvuVO /NYBxK07ob/ifXvwBzivLLmVvJF9mdG8AiKfhrJRS0/L+h5asYVbZ0S750KstJEzkkYQOqD d2wtib05dX8+iYBsu+EgJQ== X-QQ-GoodBg: 2 X-BIZMAIL-ID: 16404478094747480654 From: Jiawen Wu To: netdev@vger.kernel.org, linux@armlinux.org.uk Cc: mengyuanlou@net-swift.com, Jiawen Wu Subject: [PATCH net-next 6/6] net: txgbe: Support phylink MAC layer Date: Mon, 3 Apr 2023 14:45:28 +0800 Message-Id: <20230403064528.343866-7-jiawenwu@trustnetic.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20230403064528.343866-1-jiawenwu@trustnetic.com> References: <20230403064528.343866-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 | 20 ++-- .../net/ethernet/wangxun/txgbe/txgbe_phy.c | 110 +++++++++++++++++- .../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 caaefc20afb9..e033ed8409ce 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 @@ -206,7 +207,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); @@ -215,23 +216,15 @@ 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); 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) @@ -265,7 +258,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); @@ -296,8 +288,12 @@ 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); + if (txgbe->phylink) + 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 a00651ba021f..fee7fe175734 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" @@ -407,6 +408,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); @@ -680,7 +773,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); @@ -696,6 +791,11 @@ 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)) { + 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)); @@ -787,6 +887,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); @@ -815,6 +921,8 @@ int txgbe_init_phy(struct txgbe *txgbe) void txgbe_remove_phy(struct txgbe *txgbe) { + if (txgbe->phylink) + phylink_destroy(txgbe->phylink); if (txgbe->mdiodev) mdio_device_free(txgbe->mdiodev); if (txgbe->sfp_dev) diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h index d121edadfd09..ad3e426e49a0 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;