From patchwork Thu Oct 28 16:41:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Prasanna Vengateshan X-Patchwork-Id: 12590569 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 mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6E12AC433F5 for ; Thu, 28 Oct 2021 16:42:18 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 584D660238 for ; Thu, 28 Oct 2021 16:42:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230505AbhJ1Qoo (ORCPT ); Thu, 28 Oct 2021 12:44:44 -0400 Received: from esa.microchip.iphmx.com ([68.232.153.233]:39660 "EHLO esa.microchip.iphmx.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230467AbhJ1Qoa (ORCPT ); Thu, 28 Oct 2021 12:44:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=microchip.com; i=@microchip.com; q=dns/txt; s=mchp; t=1635439323; x=1666975323; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=h5TUqWFX65eAVTWhjiLL/x30mOubBO3aNQWs0cjZUo8=; b=kMVUO6uUlGg1aA7Ps/56mnTie28aQq1+H0kWtMLyCFNF7kmZdAkrQgRF i+Zc8Q0x5prrv/SYtAtl4RjSWlkUAAgTKOvKvaUMchRLqCLsXQ6UkdGBG govhRS98QflZB4a7B/5iQMvJS4pkrZnA9h40BQGbqWWLi07+5rpCJquAQ ungSRiCYOEjS+zmLTeCAvT/ObZoDch4Fb7PD7vgsyAKVrYicDx6ZY3w8q iMAV97dmbr3bgWAJ0Empa5ByHD7juDLWHxbq0Mf4hCgr8X1M/P7JMO5k7 W9ebpHlK5lUDjgb8HUhS5CqaZK8OzDqhLpbRRQv/4cGzP4NZie5DsbCu/ w==; IronPort-SDR: 2Ig1Fopf66IgzNwk1SFJbhBwDvJCReCJvUVVUixQp36jZTmT/tfs8LArumO77m9GsfyWlGzQW9 g71VvJTytpKtAEUI8PD1PRrIKdRWtCVe9kl43WVGQIyqUvlwYf7S5DtVF2TiQPAKs/U4ECmTCx WJ0b4ld5Tx4DQ3bmM6ALXSyrlaoIg44rAxfsEcHqH4F8fXSlTKieRk0HoMPFJrW2ZFxBGOTuYh NwfKNWwNr6Jh/OFMNla9sz1y00JnN59CsVxd4L9wPDvyguEO32rYTnGmdZVE4fTL9lmNB0M5om X4NYMGU9rKgo8aw96RmvBok6 X-IronPort-AV: E=Sophos;i="5.87,190,1631602800"; d="scan'208";a="149906205" Received: from smtpout.microchip.com (HELO email.microchip.com) ([198.175.253.82]) by esa1.microchip.iphmx.com with ESMTP/TLS/AES256-SHA256; 28 Oct 2021 09:42:02 -0700 Received: from chn-vm-ex04.mchp-main.com (10.10.85.152) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.1.2176.14; Thu, 28 Oct 2021 09:42:01 -0700 Received: from CHE-LT-I21427LX.microchip.com (10.10.115.15) by chn-vm-ex04.mchp-main.com (10.10.85.152) with Microsoft SMTP Server id 15.1.2176.14 via Frontend Transport; Thu, 28 Oct 2021 09:41:54 -0700 From: Prasanna Vengateshan To: , , , CC: , , , , , , , , , Subject: [PATCH v5 net-next 06/10] net: dsa: microchip: add support for phylink management Date: Thu, 28 Oct 2021 22:11:07 +0530 Message-ID: <20211028164111.521039-7-prasanna.vengateshan@microchip.com> X-Mailer: git-send-email 2.27.0 In-Reply-To: <20211028164111.521039-1-prasanna.vengateshan@microchip.com> References: <20211028164111.521039-1-prasanna.vengateshan@microchip.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Support for phylink_validate() and reused KSZ commmon API for phylink_mac_link_down() operation lan937x_phylink_mac_config configures the interface using lan937x_mac_config and lan937x_phylink_mac_link_up configures the speed/duplex/flow control. Currently SGMII & in-band neg are not supported & it will be added later. Signed-off-by: Prasanna Vengateshan --- drivers/net/dsa/microchip/lan937x_dev.c | 154 +++++++++++++++++++++++ drivers/net/dsa/microchip/lan937x_dev.h | 5 + drivers/net/dsa/microchip/lan937x_main.c | 98 +++++++++++++++ 3 files changed, 257 insertions(+) diff --git a/drivers/net/dsa/microchip/lan937x_dev.c b/drivers/net/dsa/microchip/lan937x_dev.c index b04881e66abd..1dcc01fb2138 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.c +++ b/drivers/net/dsa/microchip/lan937x_dev.c @@ -393,6 +393,160 @@ int lan937x_internal_phy_read(struct ksz_device *dev, int addr, int reg, return ksz_read16(dev, REG_VPHY_IND_DATA__2, val); } +static void lan937x_config_gbit(struct ksz_device *dev, bool gbit, u8 *data) +{ + if (gbit) + *data &= ~PORT_MII_NOT_1GBIT; + else + *data |= PORT_MII_NOT_1GBIT; +} + +static void lan937x_update_rgmii_tx_rx_delay(struct ksz_device *dev, int port, + bool is_tx) +{ + struct ksz_port *p = &dev->ports[port]; + u16 data16; + int reg; + u8 val; + + if (is_tx) { + reg = REG_PORT_XMII_CTRL_5; + val = p->rgmii_tx_val; + } else { + reg = REG_PORT_XMII_CTRL_4; + val = p->rgmii_rx_val; + } + + lan937x_pread16(dev, port, reg, &data16); + + /* clear tune Adjust */ + data16 &= ~PORT_TUNE_ADJ; + data16 |= (val << 7); + lan937x_pwrite16(dev, port, reg, data16); + + data16 |= PORT_DLL_RESET; + /* write DLL reset to take effect */ + lan937x_pwrite16(dev, port, reg, data16); +} + +static void lan937x_apply_rgmii_delay(struct ksz_device *dev, int port, u8 val) +{ + struct ksz_port *p = &dev->ports[port]; + + /* Clear Ingress & Egress internal delay enabled bits */ + val &= ~(PORT_RGMII_ID_EG_ENABLE | PORT_RGMII_ID_IG_ENABLE); + + if (p->rgmii_tx_val) { + lan937x_update_rgmii_tx_rx_delay(dev, port, true); + dev_info(dev->dev, "Applied rgmii tx delay for the port %d\n", + port); + val |= PORT_RGMII_ID_EG_ENABLE; + } + + if (p->rgmii_rx_val) { + lan937x_update_rgmii_tx_rx_delay(dev, port, false); + dev_info(dev->dev, "Applied rgmii rx delay for the port %d\n", + port); + val |= PORT_RGMII_ID_IG_ENABLE; + } + + /* Enable RGMII internal delays */ + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, val); +} + +void lan937x_mac_config(struct ksz_device *dev, int port, + phy_interface_t interface) +{ + u8 data8; + + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &data8); + + /* clear MII selection & set it based on interface later */ + data8 &= ~PORT_MII_SEL_M; + + /* configure MAC based on interface */ + switch (interface) { + case PHY_INTERFACE_MODE_MII: + lan937x_config_gbit(dev, false, &data8); + data8 |= PORT_MII_SEL; + break; + case PHY_INTERFACE_MODE_RMII: + lan937x_config_gbit(dev, false, &data8); + data8 |= PORT_RMII_SEL; + break; + case PHY_INTERFACE_MODE_RGMII: + lan937x_config_gbit(dev, true, &data8); + data8 |= PORT_RGMII_SEL; + break; + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_RXID: + lan937x_config_gbit(dev, true, &data8); + data8 |= PORT_RGMII_SEL; + + /* Apply rgmii internal delay for the mac */ + lan937x_apply_rgmii_delay(dev, port, data8); + + /* rgmii delay configuration is already applied above, + * hence return from here as no changes required + */ + return; + default: + dev_err(dev->dev, "Unsupported interface '%s' for port %d\n", + phy_modes(interface), port); + return; + } + + /* Write the updated value */ + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, data8); +} + +void lan937x_config_interface(struct ksz_device *dev, int port, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + u8 xmii_ctrl0, xmii_ctrl1; + + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_0, &xmii_ctrl0); + lan937x_pread8(dev, port, REG_PORT_XMII_CTRL_1, &xmii_ctrl1); + + switch (speed) { + case SPEED_1000: + lan937x_config_gbit(dev, true, &xmii_ctrl1); + break; + case SPEED_100: + lan937x_config_gbit(dev, false, &xmii_ctrl1); + xmii_ctrl0 |= PORT_MAC_SPEED_100; + break; + case SPEED_10: + lan937x_config_gbit(dev, false, &xmii_ctrl1); + xmii_ctrl0 &= ~PORT_MAC_SPEED_100; + break; + default: + dev_err(dev->dev, "Unsupported speed on port %d: %d\n", + port, speed); + return; + } + + if (duplex) + xmii_ctrl0 |= PORT_FULL_DUPLEX; + else + xmii_ctrl0 &= ~PORT_FULL_DUPLEX; + + if (tx_pause) + xmii_ctrl0 |= PORT_TX_FLOW_CTRL; + else + xmii_ctrl1 &= ~PORT_TX_FLOW_CTRL; + + if (rx_pause) + xmii_ctrl0 |= PORT_RX_FLOW_CTRL; + else + xmii_ctrl0 &= ~PORT_RX_FLOW_CTRL; + + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_0, xmii_ctrl0); + lan937x_pwrite8(dev, port, REG_PORT_XMII_CTRL_1, xmii_ctrl1); +} + void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port) { struct ksz_port *p = &dev->ports[port]; diff --git a/drivers/net/dsa/microchip/lan937x_dev.h b/drivers/net/dsa/microchip/lan937x_dev.h index 9e276f317cb3..43dc8918f63e 100644 --- a/drivers/net/dsa/microchip/lan937x_dev.h +++ b/drivers/net/dsa/microchip/lan937x_dev.h @@ -33,6 +33,11 @@ void lan937x_cfg_port_member(struct ksz_device *dev, int port, u8 member); void lan937x_port_setup(struct ksz_device *dev, int port, bool cpu_port); int lan937x_enable_spi_indirect_access(struct ksz_device *dev); +void lan937x_config_interface(struct ksz_device *dev, int port, + int speed, int duplex, + bool tx_pause, bool rx_pause); +void lan937x_mac_config(struct ksz_device *dev, int port, + phy_interface_t interface); struct mib_names { int index; diff --git a/drivers/net/dsa/microchip/lan937x_main.c b/drivers/net/dsa/microchip/lan937x_main.c index fff60b55eba8..5dfd60fbc322 100644 --- a/drivers/net/dsa/microchip/lan937x_main.c +++ b/drivers/net/dsa/microchip/lan937x_main.c @@ -326,6 +326,100 @@ static int lan937x_get_max_mtu(struct dsa_switch *ds, int port) return (FR_MAX_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN); } +static void lan937x_phylink_mac_config(struct dsa_switch *ds, int port, + unsigned int mode, + const struct phylink_link_state *state) +{ + struct ksz_device *dev = ds->priv; + + /* Internal PHYs */ + if (lan937x_is_internal_phy_port(dev, port)) + return; + + if (phylink_autoneg_inband(mode)) { + dev_err(ds->dev, "In-band AN not supported!\n"); + return; + } + + lan937x_mac_config(dev, port, state->interface); +} + +static void lan937x_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + struct phy_device *phydev, + int speed, int duplex, + bool tx_pause, bool rx_pause) +{ + struct ksz_device *dev = ds->priv; + + /* Internal PHYs */ + if (lan937x_is_internal_phy_port(dev, port)) + return; + + if (phylink_autoneg_inband(mode)) { + dev_err(ds->dev, "In-band AN not supported!\n"); + return; + } + lan937x_config_interface(dev, port, speed, duplex, + tx_pause, rx_pause); +} + +static void lan937x_phylink_validate(struct dsa_switch *ds, int port, + unsigned long *supported, + struct phylink_link_state *state) +{ + struct ksz_device *dev = ds->priv; + __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; + + /* Check for unsupported interfaces */ + if (!phy_interface_mode_is_rgmii(state->interface) && + state->interface != PHY_INTERFACE_MODE_RMII && + state->interface != PHY_INTERFACE_MODE_MII && + state->interface != PHY_INTERFACE_MODE_NA && + state->interface != PHY_INTERFACE_MODE_INTERNAL) { + bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); + dev_err(ds->dev, "Unsupported interface '%s' for port %d\n", + phy_modes(state->interface), port); + return; + } + + /* For RGMII, RMII, MII and internal TX phy port and + * as per phylink.h, when @state->interface is %PHY_INTERFACE_MODE_NA, + * phylink expects the MAC driver to return all supported link modes. + */ + if (phy_interface_mode_is_rgmii(state->interface) || + state->interface == PHY_INTERFACE_MODE_RMII || + state->interface == PHY_INTERFACE_MODE_MII || + state->interface == PHY_INTERFACE_MODE_NA || + lan937x_is_internal_base_tx_phy_port(dev, port)) { + phylink_set(mask, 10baseT_Half); + phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); + phylink_set(mask, 100baseT_Full); + phylink_set(mask, Autoneg); + phylink_set_port_modes(mask); + phylink_set(mask, Pause); + phylink_set(mask, Asym_Pause); + } + + /* For RGMII interface */ + if (phy_interface_mode_is_rgmii(state->interface) || + state->interface == PHY_INTERFACE_MODE_NA) + phylink_set(mask, 1000baseT_Full); + + /* For T1 PHY */ + if (lan937x_is_internal_base_t1_phy_port(dev, port) || + state->interface == PHY_INTERFACE_MODE_NA) { + phylink_set(mask, 100baseT1_Full); + phylink_set_port_modes(mask); + } + + bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); + bitmap_and(state->advertising, state->advertising, mask, + __ETHTOOL_LINK_MODE_MASK_NBITS); +} + const struct dsa_switch_ops lan937x_switch_ops = { .get_tag_protocol = lan937x_get_tag_protocol, .setup = lan937x_setup, @@ -338,6 +432,10 @@ const struct dsa_switch_ops lan937x_switch_ops = { .port_fast_age = ksz_port_fast_age, .port_max_mtu = lan937x_get_max_mtu, .port_change_mtu = lan937x_change_mtu, + .phylink_validate = lan937x_phylink_validate, + .phylink_mac_link_down = ksz_mac_link_down, + .phylink_mac_config = lan937x_phylink_mac_config, + .phylink_mac_link_up = lan937x_phylink_mac_link_up, }; int lan937x_switch_register(struct ksz_device *dev)