From patchwork Wed Nov 25 23:24:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Majewski X-Patchwork-Id: 11932347 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 X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9866CC64E7B for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5C01020872 for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733195AbgKYXZ4 (ORCPT ); Wed, 25 Nov 2020 18:25:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39142 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730073AbgKYXZy (ORCPT ); Wed, 25 Nov 2020 18:25:54 -0500 Received: from mail-out.m-online.net (mail-out.m-online.net [IPv6:2001:a60:0:28:0:1:25:1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1A0FFC0613D4 for ; Wed, 25 Nov 2020 15:25:54 -0800 (PST) Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4ChH7b4jj5z1rwZq; Thu, 26 Nov 2020 00:25:45 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4ChH7Y1vZ5z1vdfs; Thu, 26 Nov 2020 00:25:45 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id Bo2OedDOC47N; Thu, 26 Nov 2020 00:25:43 +0100 (CET) X-Auth-Info: Pw9YCvMdnOzlHdaksvWkRNQhWgJkn2CYCowWoZ/VK/w= Received: from localhost.localdomain (89-64-5-98.dynamic.chello.pl [89.64.5.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 26 Nov 2020 00:25:43 +0100 (CET) From: Lukasz Majewski To: Fugang Duan , "David S . Miller" , Jakub Kicinski , netdev@vger.kernel.org, Andrew Lunn , Fabio Estevam , Vivien Didelot Cc: NXP Linux Team , Florian Fainelli , Vladimir Oltean , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peng Fan , stefan.agner@toradex.com, krzk@kernel.org, Shawn Guo , Lukasz Majewski Subject: [RFC 1/4] net: fec: Move some defines to ./drivers/net/ethernet/freescale/fec.h header Date: Thu, 26 Nov 2020 00:24:56 +0100 Message-Id: <20201125232459.378-2-lukma@denx.de> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201125232459.378-1-lukma@denx.de> References: <20201125232459.378-1-lukma@denx.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC After this change ECR (control register) defines are moved to fec.h, so they can be reused by L2 switch code. Signed-off-by: Lukasz Majewski --- drivers/net/ethernet/freescale/fec.h | 3 +++ drivers/net/ethernet/freescale/fec_main.c | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 832a2175636d..c555a421f647 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -189,6 +189,9 @@ #define FEC_RXIC2 0xfff #endif /* CONFIG_M5272 */ +/* FEC ECR bits definition */ +#define FEC_ECR_MAGICEN (1 << 2) +#define FEC_ECR_SLEEP (1 << 3) /* * Define the buffer descriptor structure. diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index fb37816a74db..bd29c84fd89a 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -249,9 +249,6 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); #define FEC_MMFR_RA(v) ((v & 0x1f) << 18) #define FEC_MMFR_TA (2 << 16) #define FEC_MMFR_DATA(v) (v & 0xffff) -/* FEC ECR bits definition */ -#define FEC_ECR_MAGICEN (1 << 2) -#define FEC_ECR_SLEEP (1 << 3) #define FEC_MII_TIMEOUT 30000 /* us */ From patchwork Wed Nov 25 23:24:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Majewski X-Patchwork-Id: 11932349 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 X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4B419C6379D for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 172A820B1F for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731655AbgKYXZx (ORCPT ); Wed, 25 Nov 2020 18:25:53 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:53264 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730073AbgKYXZw (ORCPT ); Wed, 25 Nov 2020 18:25:52 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4ChH7c6Sjlz1qs3T; Thu, 26 Nov 2020 00:25:48 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4ChH7c4fPPz1vdfr; Thu, 26 Nov 2020 00:25:48 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id g3MDGMLJmW-c; Thu, 26 Nov 2020 00:25:45 +0100 (CET) X-Auth-Info: IeiHtiPYoFdCUa+1+vvG45H4aIS8SmrvEwdzEGWEk6I= Received: from localhost.localdomain (89-64-5-98.dynamic.chello.pl [89.64.5.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 26 Nov 2020 00:25:45 +0100 (CET) From: Lukasz Majewski To: Fugang Duan , "David S . Miller" , Jakub Kicinski , netdev@vger.kernel.org, Andrew Lunn , Fabio Estevam , Vivien Didelot Cc: NXP Linux Team , Florian Fainelli , Vladimir Oltean , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peng Fan , stefan.agner@toradex.com, krzk@kernel.org, Shawn Guo , Lukasz Majewski Subject: [RFC 2/4] net: dsa: Provide DSA driver for NXP's More Than IP L2 switch Date: Thu, 26 Nov 2020 00:24:57 +0100 Message-Id: <20201125232459.378-3-lukma@denx.de> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201125232459.378-1-lukma@denx.de> References: <20201125232459.378-1-lukma@denx.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This change provides driver for DSA (Distributed Switch Architecture) subsystem for i.MX28 SoC (imx287 to be precise). This code just is responsible for configuring this device as L2 bridge (no vlan, port separation supported). This driver shall be regarded as a complementary one for NXP's FEC (fec_main.c). Signed-off-by: Lukasz Majewski --- drivers/net/dsa/Kconfig | 11 + drivers/net/dsa/Makefile | 1 + drivers/net/dsa/mtip-l2switch.c | 399 ++++++++++++++++++++++++++++++++ drivers/net/dsa/mtip-l2switch.h | 239 +++++++++++++++++++ 4 files changed, 650 insertions(+) create mode 100644 drivers/net/dsa/mtip-l2switch.c create mode 100644 drivers/net/dsa/mtip-l2switch.h diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 468b3c4273c5..52013eb5afb3 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -132,4 +132,15 @@ config NET_DSA_VITESSE_VSC73XX_PLATFORM This enables support for the Vitesse VSC7385, VSC7388, VSC7395 and VSC7398 SparX integrated ethernet switches, connected over a CPU-attached address bus and work in memory-mapped I/O mode. + +config NET_DSA_MTIP_L2SW + tristate "MoreThanIP L2 switch support (IMX)" + depends on OF + depends on NET_DSA + depends on ARCH_MXS + select FIXED_PHY + help + This enables support for the MoreThan IP on i.MX SoCs (e.g. iMX28) + L2 switch. + endmenu diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile index 4a943ccc2ca4..b947dc54db09 100644 --- a/drivers/net/dsa/Makefile +++ b/drivers/net/dsa/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_NET_DSA_SMSC_LAN9303_MDIO) += lan9303_mdio.o obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX) += vitesse-vsc73xx-core.o obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_PLATFORM) += vitesse-vsc73xx-platform.o obj-$(CONFIG_NET_DSA_VITESSE_VSC73XX_SPI) += vitesse-vsc73xx-spi.o +obj-$(CONFIG_NET_DSA_MTIP_L2SW) += mtip-l2switch.o obj-y += b53/ obj-y += microchip/ obj-y += mv88e6xxx/ diff --git a/drivers/net/dsa/mtip-l2switch.c b/drivers/net/dsa/mtip-l2switch.c new file mode 100644 index 000000000000..2ecdf82ccd6c --- /dev/null +++ b/drivers/net/dsa/mtip-l2switch.c @@ -0,0 +1,399 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Lukasz Majewski + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtip-l2switch.h" +#include "../ethernet/freescale/fec.h" + +static int mtipl2_en_rx(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (!fep->hwpsw) + return -ENODEV; + + writel(MCF_ESW_RDAR_R_DES_ACTIVE, fep->hwpsw + MCF_ESW_R_RDAR); + + return 0; +} + +static int mtipl2_set_rx_buf_size(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (!fep->hwpsw) + return -ENODEV; + + /* Set the max rx buffer size */ + writel(L2SW_PKT_MAXBLR_SIZE, fep->hwpsw + MCF_ESW_R_BUFF_SIZE); + + return 0; +} + +static int mtipl2_set_ints(struct net_device *ndev) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + + if (!fep->hwpsw) + return -ENODEV; + + /* Clear all pending interrupts */ + writel(0xffffffff, fep->hwpsw + FEC_IEVENT); + + /* Enable interrupts we wish to service */ + writel(MCF_ESW_IMR_TXF | MCF_ESW_IMR_RXB | MCF_ESW_IMR_TXB, + fep->hwpsw + FEC_IMASK); + + return 0; +} + +static void read_atable(struct mtipl2sw_priv *priv, int index, + unsigned long *read_lo, unsigned long *read_hi) +{ + unsigned long atable_base = (unsigned long)priv->hwentry; + + *read_lo = readl((const volatile void*)atable_base + (index << 3)); + *read_hi = readl((const volatile void*)atable_base + (index << 3) + 4); +} + +static void write_atable(struct mtipl2sw_priv *priv, int index, + unsigned long write_lo, unsigned long write_hi) +{ + unsigned long atable_base = (unsigned long)priv->hwentry; + + writel(write_lo, (volatile void *)atable_base + (index << 3)); + writel(write_hi, (volatile void *)atable_base + (index << 3) + 4); +} + +/* + * Clear complete MAC Look Up Table + */ +static void esw_clear_atable(struct mtipl2sw_priv *priv) +{ + int index; + for (index = 0; index < 2048; index++) + write_atable(priv, index, 0, 0); +} + +static void l2_enet_set_mac(struct net_device *ndev, void __iomem *hwp) +{ + writel(ndev->dev_addr[3] | + ndev->dev_addr[2] << 8 | + ndev->dev_addr[1] << 16 | + ndev->dev_addr[0] << 24, + hwp + FEC_ADDR_LOW); + + writel(ndev->dev_addr[5] << 16 | + (ndev->dev_addr[4] + (unsigned char)(0)) << 24, + hwp + FEC_ADDR_HIGH); +} + +static void l2_enet_reset(struct net_device *ndev, int port, + struct phy_device *phy) +{ + struct fec_enet_private *fep = netdev_priv(ndev); + void __iomem *hwp = fep->hwp; + + if (port == 1) + hwp += ENET_L2_SW_PORT1_OFFSET; + + /* ECR */ + writel(FEC_ECR_MAGICEN, hwp + FEC_ECNTRL); + /* EMRBR */ + writel(L2SW_PKT_MAXBLR_SIZE, hwp + MCF_FEC_EMRBR); + + /* + * PHY speed for both MACs (via mac0 adjustement is setup + * in fec_restart() + */ + + /* EIR */ + writel(0, hwp + FEC_IEVENT); + /* IAUR */ + writel(0, hwp + FEC_HASH_TABLE_HIGH); + /* IALR */ + writel(0, hwp + FEC_HASH_TABLE_LOW); + /* GAUR */ + writel(0, hwp + FEC_GRP_HASH_TABLE_HIGH); + /* GALR */ + writel(0, hwp + FEC_GRP_HASH_TABLE_LOW); + /* EMRBR */ + writel(L2SW_PKT_MAXBLR_SIZE, hwp + MCF_FEC_EMRBR); + + /* Set the MAC address for the LAN{12} net device */ + l2_enet_set_mac(ndev, hwp); + + /* RCR */ + if (phy && phy->speed == SPEED_100) { + if (phy->duplex == DUPLEX_FULL) { + /* full duplex mode */ + writel((readl(hwp + FEC_R_CNTRL) + | MCF_FEC_RCR_FCE | MCF_FEC_RCR_PROM) + & ~(MCF_FEC_RCR_RMII_10BASET | + MCF_FEC_RCR_DRT), + hwp + FEC_R_CNTRL); + } else { + /* half duplex mode */ + writel((readl(hwp + FEC_R_CNTRL) + | MCF_FEC_RCR_FCE | MCF_FEC_RCR_PROM + | MCF_FEC_RCR_DRT) + & ~(MCF_FEC_RCR_RMII_10BASET), + hwp + FEC_R_CNTRL); + } + } else { + if (phy->duplex == DUPLEX_FULL) { + /* full duplex mode */ + writel((readl(hwp + FEC_R_CNTRL) + | MCF_FEC_RCR_FCE | MCF_FEC_RCR_PROM + | MCF_FEC_RCR_RMII_10BASET) & + ~(MCF_FEC_RCR_DRT), + hwp + FEC_R_CNTRL); + } else { + /* half duplex mode */ + writel(readl(hwp + FEC_R_CNTRL) + | MCF_FEC_RCR_FCE | MCF_FEC_RCR_PROM + | MCF_FEC_RCR_RMII_10BASET | MCF_FEC_RCR_DRT, + hwp + FEC_R_CNTRL); + } + } + + /* + * MII Gasket configuration is performed for MAC0 (which shall be + * correct for both MACs) in fec_restart(). + * + * Configuration: RMII, 50 MHz, no loopback, no echo + */ + + /* TCR */ + if (phy->duplex == DUPLEX_FULL) + writel(0x1c, hwp + FEC_X_CNTRL); + else + writel(0x18, hwp + FEC_X_CNTRL); + + /* ECR */ + writel(readl(hwp + FEC_ECNTRL) | FEC_ECNTRL_ETHER_EN, + hwp + FEC_ECNTRL); +} + +static enum dsa_tag_protocol +mtipl2_get_tag_protocol(struct dsa_switch *ds, int port, + enum dsa_tag_protocol mp) +{ + return DSA_TAG_PROTO_NONE; +} + +static int mtip_sw_config(struct dsa_switch *ds) +{ + struct mtipl2sw_priv *priv = (struct mtipl2sw_priv *)ds->priv; + const struct dsa_port *pm = dsa_to_port(ds, priv->cpu_port); + + /* + * L2 switch - reset + */ + writel(MCF_ESW_MODE_SW_RST, &priv->fecp->ESW_MODE); + udelay(10); + + /* Configure switch*/ + writel(MCF_ESW_MODE_STATRST, &priv->fecp->ESW_MODE); + writel(MCF_ESW_MODE_SW_EN, &priv->fecp->ESW_MODE); + + /* + * Transmit/Receive on ports 1,2 (including port 0) + * will be enabled when DSA port is enabled + */ + + /* Management port configuration, make port 0 as management port */ + writel(0, &priv->fecp->ESW_BMPC); + + /* + * Set backpressure threshold to minimize discarded frames + * during due to congestion. + */ + writel(P0BC_THRESHOLD, &priv->fecp->ESW_P0BCT); + + mtipl2_set_rx_buf_size(pm->master); + + /* Enable broadcast on all ports */ + writel(0x7, &priv->fecp->ESW_DBCR); + + /* Enable multicast on all ports */ + writel(0x7, &priv->fecp->ESW_DMCR); + + esw_clear_atable(priv); + mtipl2_set_ints(pm->master); + + return 0; +} + +static int mtipl2_setup(struct dsa_switch *ds) +{ + struct mtipl2sw_priv *priv = (struct mtipl2sw_priv *)ds->priv; + + /* Make sure that port 2 is the cpu port */ + if (dsa_is_cpu_port(ds, 2)) + priv->cpu_port = 2; + else + return -EINVAL; + + mtip_sw_config(ds); + return 0; +} + +void mtipl2_adjust_link (struct dsa_switch *ds, int port, + struct phy_device *phy) +{ + struct mtipl2sw_priv *priv = (struct mtipl2sw_priv *)ds->priv; + const struct dsa_port *pm = dsa_to_port(ds, priv->cpu_port); + + /* Set port speed */ + switch (phy->speed) { + case 10: + pr_err("fec: %s: PHY speed 10 [%d]\n", __func__, port); + break; + case 100: + pr_err("fec: %s: PHY speed 100 [%d]\n", __func__, port); + break; + default: + pr_err("port%d link speed %dMbps not supported.\n", port, + phy->speed); + return; + } + + /* Set duplex mode */ + if (phy->duplex == DUPLEX_FULL) + pr_err("fec: %s: LINK UPDATE DUPLEX_FULL [%d]\n", __func__, + port); + + /* Reset and configure L2 switch port */ + l2_enet_reset(pm->master, port, phy); + + /* + * The L2 switch R_RDAR register needs to be updated + * after the port is enabled. + */ + mtipl2_en_rx(pm->master); +} + +int mtipl2_port_enable (struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mtipl2sw_priv *priv = (struct mtipl2sw_priv *)ds->priv; + struct dsa_port *pm = dsa_to_port(ds, priv->cpu_port); + u32 l2_ports_en; + + pr_err("fec: %s: PORT ENABLE %d\n", __func__, port); + + /* The CPU port shall be always enabled - as it is a "fixed-link" one */ + if (port == priv->cpu_port || priv->cpu_port == -1) + return 0; + + /* Enable tx/rx on L2 switch ports */ + l2_ports_en = readl(&priv->fecp->ESW_PER); + if (!(l2_ports_en & MCF_ESW_ENA_PORT_0)) + l2_ports_en = MCF_ESW_ENA_PORT_0; + + if (port == 0 && !(l2_ports_en & MCF_ESW_ENA_PORT_1)) + l2_ports_en |= MCF_ESW_ENA_PORT_1; + + if (port == 1 && !(l2_ports_en & MCF_ESW_ENA_PORT_2)) + l2_ports_en |= MCF_ESW_ENA_PORT_2; + + writel(l2_ports_en, &priv->fecp->ESW_PER); + + /* + * Check if MAC IP block is already enabled (after switch initializtion) + * or if we need to enable it after mtipl2_port_disable was called. + */ + + return 0; +} + +static void mtipl2_port_disable (struct dsa_switch *ds, int port) +{ + struct mtipl2sw_priv *priv = (struct mtipl2sw_priv *)ds->priv; + struct dsa_port *pm = dsa_to_port(ds, priv->cpu_port); + u32 l2_ports_en; + + pr_err("fec: %s: PORT DISABLE %d\n", __func__, port); + + l2_ports_en = readl(&priv->fecp->ESW_PER); + if (port == 0) + l2_ports_en &= ~MCF_ESW_ENA_PORT_1; + + if (port == 1) + l2_ports_en &= ~MCF_ESW_ENA_PORT_2; + + /* Finally disable tx/rx on port 0 */ + if (!(l2_ports_en & MCF_ESW_ENA_PORT_1) && + !(l2_ports_en & MCF_ESW_ENA_PORT_2)) + l2_ports_en &= ~MCF_ESW_ENA_PORT_0; + + writel(l2_ports_en, &priv->fecp->ESW_PER); +} + +static const struct dsa_switch_ops mtipl2_switch_ops = { + .get_tag_protocol = mtipl2_get_tag_protocol, + .setup = mtipl2_setup, + .adjust_link = mtipl2_adjust_link, + .port_enable = mtipl2_port_enable, + .port_disable = mtipl2_port_disable, +}; + +static int mtipl2_sw_probe(struct platform_device *pdev) +{ + struct mtipl2sw_priv *priv; + struct resource *r; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->fecp = devm_ioremap_resource(&pdev->dev, r); + + r = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->hwentry = devm_ioremap_resource(&pdev->dev, r); + + priv->ds = devm_kzalloc(&pdev->dev, sizeof(*priv->ds), GFP_KERNEL); + if (!priv->ds) + return -ENOMEM; + + priv->ds->dev = &pdev->dev; + priv->ds->num_ports = MTIPL2SW_NUM_PORTS; + priv->ds->priv = priv; + priv->ds->ops = &mtipl2_switch_ops; + + return dsa_register_switch(priv->ds); +} + +static const struct of_device_id mtipl2_of_match[] = { + { .compatible = "imx,mtip-l2switch" }, + { /* sentinel */ }, +}; + +static struct platform_driver mtipl2plat_driver = { + .probe = mtipl2_sw_probe, + .driver = { + .name = "mtipl2sw", + .of_match_table = mtipl2_of_match, + }, +}; + +module_platform_driver(mtipl2plat_driver); + +MODULE_AUTHOR("Lukasz Majewski "); +MODULE_DESCRIPTION("Driver for MTIP L2 on SOC switch"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:mtipl2sw"); diff --git a/drivers/net/dsa/mtip-l2switch.h b/drivers/net/dsa/mtip-l2switch.h new file mode 100644 index 000000000000..ea354ae99ecd --- /dev/null +++ b/drivers/net/dsa/mtip-l2switch.h @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 DENX Software Engineering GmbH + * Lukasz Majewski + */ + +#ifndef __MTIP_L2SWITCH_H_ +#define __MTIP_L2SWITCH_H_ + +#define MTIPL2SW_NUM_PORTS 3 + +#define ENET_SWI_PHYS_ADDR_OFFSET 0x8000 +#define ENET_L2_SW_PORT1_OFFSET 0x4000 +/* Bit definitions and macros for MCF_ESW_MODE */ +#define MCF_ESW_MODE_SW_RST BIT(0) +#define MCF_ESW_MODE_SW_EN BIT(1) +#define MCF_ESW_MODE_STATRST BIT(31) + +/* Port 0 backpressure congestion threshold */ +#define P0BC_THRESHOLD 0x40 + +struct esw_output_queue_status { + unsigned long ESW_MMSR; + unsigned long ESW_LMT; + unsigned long ESW_LFC; + unsigned long ESW_PCSR; + unsigned long ESW_IOSR; + unsigned long ESW_QWT; + unsigned long esw_reserved; + unsigned long ESW_P0BCT; +}; +struct esw_statistics_status { + /* + * Total number of incoming frames processed + * but discarded in switch + */ + unsigned long ESW_DISCN; + /*Sum of bytes of frames counted in ESW_DISCN*/ + unsigned long ESW_DISCB; + /* + * Total number of incoming frames processed + * but not discarded in switch + */ + unsigned long ESW_NDISCN; + /*Sum of bytes of frames counted in ESW_NDISCN*/ + unsigned long ESW_NDISCB; +}; + +struct esw_port_statistics_status { + /*outgoing frames discarded due to transmit queue congestion*/ + unsigned long MCF_ESW_POQC; + /*incoming frames discarded due to VLAN domain mismatch*/ + unsigned long MCF_ESW_PMVID; + /*incoming frames discarded due to untagged discard*/ + unsigned long MCF_ESW_PMVTAG; + /*incoming frames discarded due port is in blocking state*/ + unsigned long MCF_ESW_PBL; +}; + +struct l2switch_t { + unsigned long ESW_REVISION; + unsigned long ESW_SCRATCH; + unsigned long ESW_PER; + unsigned long reserved0[1]; + unsigned long ESW_VLANV; + unsigned long ESW_DBCR; + unsigned long ESW_DMCR; + unsigned long ESW_BKLR; + unsigned long ESW_BMPC; + unsigned long ESW_MODE; + unsigned long ESW_VIMSEL; + unsigned long ESW_VOMSEL; + unsigned long ESW_VIMEN; + unsigned long ESW_VID;/*0x34*/ + /*from 0x38 0x3C*/ + unsigned long esw_reserved0[2]; + unsigned long ESW_MCR;/*0x40*/ + unsigned long ESW_EGMAP; + unsigned long ESW_INGMAP; + unsigned long ESW_INGSAL; + unsigned long ESW_INGSAH; + unsigned long ESW_INGDAL; + unsigned long ESW_INGDAH; + unsigned long ESW_ENGSAL; + unsigned long ESW_ENGSAH; + unsigned long ESW_ENGDAL; + unsigned long ESW_ENGDAH; + unsigned long ESW_MCVAL;/*0x6C*/ + /*from 0x70--0x7C*/ + unsigned long esw_reserved1[4]; + unsigned long ESW_MMSR;/*0x80*/ + unsigned long ESW_LMT; + unsigned long ESW_LFC; + unsigned long ESW_PCSR; + unsigned long ESW_IOSR; + unsigned long ESW_QWT;/*0x94*/ + unsigned long esw_reserved2[1];/*0x98*/ + unsigned long ESW_P0BCT;/*0x9C*/ + /*from 0xA0-0xB8*/ + unsigned long esw_reserved3[7]; + unsigned long ESW_P0FFEN;/*0xBC*/ + unsigned long ESW_PSNP[8]; + unsigned long ESW_IPSNP[8]; + unsigned long ESW_PVRES[3]; + /*from 0x10C-0x13C*/ + unsigned long esw_reserved4[13]; + unsigned long ESW_IPRES;/*0x140*/ + /*from 0x144-0x17C*/ + unsigned long esw_reserved5[15]; + unsigned long ESW_PRES[3]; + /*from 0x18C-0x1FC*/ + unsigned long esw_reserved6[29]; + unsigned long ESW_PID[3]; + /*from 0x20C-0x27C*/ + unsigned long esw_reserved7[29]; + unsigned long ESW_VRES[32]; + unsigned long ESW_DISCN;/*0x300*/ + unsigned long ESW_DISCB; + unsigned long ESW_NDISCN; + unsigned long ESW_NDISCB;/*0xFC0DC30C*/ + struct esw_port_statistics_status port_statistics_status[3]; + /*from 0x340-0x400*/ + unsigned long esw_reserved8[48]; + + /*0xFC0DC400---0xFC0DC418*/ + /*unsigned long MCF_ESW_ISR;*/ + unsigned long switch_ievent; /* Interrupt event reg */ + /*unsigned long MCF_ESW_IMR;*/ + unsigned long switch_imask; /* Interrupt mask reg */ + /*unsigned long MCF_ESW_RDSR;*/ + unsigned long fec_r_des_start; /* Receive descriptor ring */ + /*unsigned long MCF_ESW_TDSR;*/ + unsigned long fec_x_des_start; /* Transmit descriptor ring */ + /*unsigned long MCF_ESW_MRBR;*/ + unsigned long fec_r_buff_size; /* Maximum receive buff size */ + /*unsigned long MCF_ESW_RDAR;*/ + unsigned long fec_r_des_active; /* Receive descriptor reg */ + /*unsigned long MCF_ESW_TDAR;*/ + unsigned long fec_x_des_active; /* Transmit descriptor reg */ + /*from 0x420-0x4FC*/ + unsigned long esw_reserved9[57]; + + /*0xFC0DC500---0xFC0DC508*/ + unsigned long ESW_LREC0; + unsigned long ESW_LREC1; + unsigned long ESW_LSR; +}; + +struct AddrTable64bEntry { + unsigned int lo; /* lower 32 bits */ + unsigned int hi; /* upper 32 bits */ +}; + +struct eswAddrTable_t { + struct AddrTable64bEntry eswTable64bEntry[2048]; +}; + +struct mtipl2sw_priv { + struct dsa_switch *ds; + struct device *dev; + + /* CPU port number */ + int cpu_port; + /* Registers to configure/setup L2 switch IP block */ + struct l2switch_t *fecp; + + /* Look-up MAC address table start from 0x800FC000 */ + struct eswAddrTable_t *hwentry; +}; + + +#define MCF_ESW_RDAR_R_DES_ACTIVE BIT(24) +#define FEC_MIIGSK_EN BIT(2) + +/* Bit definitions and macros for MCF_ESW_IMR */ +#define MCF_ESW_IMR_EBERR (0x00000001) +#define MCF_ESW_IMR_RXB (0x00000002) +#define MCF_ESW_IMR_RXF (0x00000004) +#define MCF_ESW_IMR_TXB (0x00000008) +#define MCF_ESW_IMR_TXF (0x00000010) +#define MCF_ESW_IMR_QM (0x00000020) +#define MCF_ESW_IMR_OD0 (0x00000040) +#define MCF_ESW_IMR_OD1 (0x00000080) +#define MCF_ESW_IMR_OD2 (0x00000100) +#define MCF_ESW_IMR_LRN (0x00000200) + +/* HW_ENET_SWI_PORT_ENA */ +#define MCF_ESW_ENA_TRANSMIT_0 BIT(0) +#define MCF_ESW_ENA_TRANSMIT_1 BIT(1) +#define MCF_ESW_ENA_TRANSMIT_2 BIT(2) + +#define MCF_ESW_ENA_RECEIVE_0 BIT(16) +#define MCF_ESW_ENA_RECEIVE_1 BIT(17) +#define MCF_ESW_ENA_RECEIVE_2 BIT(18) + +#define MCF_ESW_ENA_PORT_0 (MCF_ESW_ENA_TRANSMIT_0 | MCF_ESW_ENA_RECEIVE_0) +#define MCF_ESW_ENA_PORT_1 (MCF_ESW_ENA_TRANSMIT_1 | MCF_ESW_ENA_RECEIVE_1) +#define MCF_ESW_ENA_PORT_2 (MCF_ESW_ENA_TRANSMIT_2 | MCF_ESW_ENA_RECEIVE_2) + +#define MCF_FEC_RCR_DRT (0x00000002) +#define MCF_FEC_RCR_PROM (0x00000008) +#define MCF_FEC_RCR_FCE (0x00000020) +#define MCF_FEC_RCR_RMII_MODE (0x00000100) +#define MCF_FEC_RCR_RMII_10BASET (0x00000200) +#define MCF_FEC_RCR_MAX_FL(x) (((x)&0x00003FFF)<<16) +#define MCF_FEC_RCR_CRC_FWD (0x00004000) +#define MCF_FEC_RCR_NO_LGTH_CHECK (0x40000000) +#define MCF_FEC_TCR_FDEN (0x00000004) + +#define MCF_FEC_ECR_RESET (0x00000001) +#define MCF_FEC_ECR_ETHER_EN (0x00000002) +#define MCF_FEC_ECR_MAGIC_ENA (0x00000004) +#define MCF_FEC_ECR_ENA_1588 (0x00000010) + +/* L2 switch Maximum receive buff size */ +#define MCF_ESW_R_BUFF_SIZE 0x14 +/* L2 switch Receive Descriptor Active Register */ +#define MCF_ESW_R_RDAR 0x18 + +/* + * MCF_FEC_EMRBR corresponds to FEC_R_BUFF_SIZE_0 in fec main driver. + * It is duplicated as for L2 switch FEC_R_BUFF_SIZE_0 is aliased + * to different offset in switch IC. Hence the need to introduce new + * #define. + */ +#define MCF_FEC_EMRBR (0x188) + +#define MCF_FEC_ERDSR(x) ((x) << 2) + +#define MCF_ECR_ETHER_EN 1 +#define FEC_ECNTRL_ETHER_EN BIT(1) +/* + * The Switch stores dest/src/type, data, and checksum for receive packets. + */ +#define L2SW_PKT_MAXBUF_SIZE 1518 +#define L2SW_PKT_MINBUF_SIZE 64 +#define L2SW_PKT_MAXBLR_SIZE 1520 + +#endif /* __MTIP_L2SWITCH_H_ */ From patchwork Wed Nov 25 23:24:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Majewski X-Patchwork-Id: 11932351 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 X-Spam-Level: X-Spam-Status: No, score=-21.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,MENTIONS_GIT_HOSTING,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CDDF4C64E7C for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A16F8208B8 for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732992AbgKYXZ4 (ORCPT ); Wed, 25 Nov 2020 18:25:56 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39144 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731723AbgKYXZy (ORCPT ); Wed, 25 Nov 2020 18:25:54 -0500 Received: from mail-out.m-online.net (mail-out.m-online.net [IPv6:2001:a60:0:28:0:1:25:1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21E54C0617A7; Wed, 25 Nov 2020 15:25:54 -0800 (PST) Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4ChH7h3WTQz1rwbQ; Thu, 26 Nov 2020 00:25:52 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4ChH7h1yxCz1vdfr; Thu, 26 Nov 2020 00:25:52 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id 0tq-JewcryuK; Thu, 26 Nov 2020 00:25:49 +0100 (CET) X-Auth-Info: tqwjHQgo7y6AUtrE4M0Yu1GOtBSUxuquCxt9UU6FS3o= Received: from localhost.localdomain (89-64-5-98.dynamic.chello.pl [89.64.5.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 26 Nov 2020 00:25:48 +0100 (CET) From: Lukasz Majewski To: Fugang Duan , "David S . Miller" , Jakub Kicinski , netdev@vger.kernel.org, Andrew Lunn , Fabio Estevam , Vivien Didelot Cc: NXP Linux Team , Florian Fainelli , Vladimir Oltean , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peng Fan , stefan.agner@toradex.com, krzk@kernel.org, Shawn Guo , Lukasz Majewski Subject: [RFC 3/4] net: imx: l2switch: Adjust fec_main.c to provide support for L2 switch Date: Thu, 26 Nov 2020 00:24:58 +0100 Message-Id: <20201125232459.378-4-lukma@denx.de> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201125232459.378-1-lukma@denx.de> References: <20201125232459.378-1-lukma@denx.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org X-Patchwork-State: RFC This patch provides the code for re-using generic FEC i.MX code for L2 switch. The trick here is to set eth0 controller as a "fixed-link" and then use DSA subsystem to create lan{12} network devices for ports. The internal connection diagram can be found here [0]. This code has been developed on i.MX287 device, but L2 switch (from More ThanIP) can be also found on e.g. NXP's Vybrid VF610 SoC. To reuse as much code as possible it was also necessary to introduce fec_hwp() wrapper, which either returns pointer to MAC or L2 switch interrupt and buffer descriptors. Following registers shall be used with it: FEC_{IEVENT|IMASK}, FEC_R_DES_ACTIVE_0, FEC_X_DES_ACTIVE_0, FEC_R_DES_START_0, FEC_X_DES_START_0 The biggest issue was to divide the legacy driver's code (from 2.6.35 [1]) between contemporary kernel FEC driver and DSA subsystem [2]. Only the code for setting up interrupts is protected by #ifdef CONFIG_NET_DSA_MTIP_L2SW In other cases the fep->l2switch flag is checked (and the code is compiled into the driver) as there are only a few alterations (i.e. readl/writel) to the generic FEC code. The most intrusive changes when L2 switch is used: - FEC clock enabled It is necessary to allow DSA normal operation (it shall be enabled as long as L2 switch is used) - Disable RACC (Receive Data Accelerator) When this feature is enabled the data is shifted by 16 bits and hence received packets are malformed when we try to pass data from one switch port to another. - Enable PROMISC mode for ENET-MAC{01} ports - L2 switch shall pass the whole pkt_len packet. Current FEC code subtract 4 to remove FCS Links: [0] - Chapter 29.3.1 in "i.MX28 Applications Processor Reference Manual, Rev. 2, 08/2013" [1] >From 2.6 i.MX kernel: Repo: git://git.freescale.com/imx/linux-2.6-imx.git Branch: imx_2.6.35_maintain SHA1: b3912bb8a4caf3ec50909135e88af959982c43ca [2] - https://github.com/lmajewski/linux-imx28-l2switch/commits/master Signed-off-by: Lukasz Majewski --- drivers/net/ethernet/freescale/fec.h | 39 ++++++ drivers/net/ethernet/freescale/fec_main.c | 145 +++++++++++++++++++--- 2 files changed, 166 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index c555a421f647..acca7cbf9e6b 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -29,8 +29,13 @@ */ #define FEC_IEVENT 0x004 /* Interrupt event reg */ #define FEC_IMASK 0x008 /* Interrupt mask reg */ +#ifdef CONFIG_NET_DSA_MTIP_L2SW +#define FEC_R_DES_ACTIVE_0 0x018 /* L2 switch Receive descriptor reg */ +#define FEC_X_DES_ACTIVE_0 0x01C /* L2 switch Transmit descriptor reg */ +#else #define FEC_R_DES_ACTIVE_0 0x010 /* Receive descriptor reg */ #define FEC_X_DES_ACTIVE_0 0x014 /* Transmit descriptor reg */ +#endif #define FEC_ECNTRL 0x024 /* Ethernet control reg */ #define FEC_MII_DATA 0x040 /* MII manage frame reg */ #define FEC_MII_SPEED 0x044 /* MII speed control reg */ @@ -59,8 +64,13 @@ #define FEC_R_DES_START_2 0x16c /* Receive descriptor ring 2 */ #define FEC_X_DES_START_2 0x170 /* Transmit descriptor ring 2 */ #define FEC_R_BUFF_SIZE_2 0x174 /* Maximum receive buff ring2 size */ +#ifdef CONFIG_NET_DSA_MTIP_L2SW +#define FEC_R_DES_START_0 0x0C /* L2 switch Receive descriptor ring */ +#define FEC_X_DES_START_0 0x10 /* L2 switch Transmit descriptor ring */ +#else #define FEC_R_DES_START_0 0x180 /* Receive descriptor ring */ #define FEC_X_DES_START_0 0x184 /* Transmit descriptor ring */ +#endif #define FEC_R_BUFF_SIZE_0 0x188 /* Maximum receive buff size */ #define FEC_R_FIFO_RSFL 0x190 /* Receive FIFO section full threshold */ #define FEC_R_FIFO_RSEM 0x194 /* Receive FIFO section empty threshold */ @@ -363,13 +373,25 @@ struct bufdesc_ex { #define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ #define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ #define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ +#ifdef CONFIG_NET_DSA_MTIP_L2SW +#define FEC_ENET_TXF_0 BIT(4) +#define FEC_ENET_TXF_1 0 +#define FEC_ENET_TXF_2 0 +#else #define FEC_ENET_TXF_0 ((uint)0x08000000) /* Full frame transmitted */ #define FEC_ENET_TXF_1 ((uint)0x00000008) /* Full frame transmitted */ #define FEC_ENET_TXF_2 ((uint)0x00000080) /* Full frame transmitted */ +#endif #define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ +#ifdef CONFIG_NET_DSA_MTIP_L2SW +#define FEC_ENET_RXF_0 BIT(2) +#define FEC_ENET_RXF_1 0 +#define FEC_ENET_RXF_2 0 +#else #define FEC_ENET_RXF_0 ((uint)0x02000000) /* Full frame received */ #define FEC_ENET_RXF_1 ((uint)0x00000002) /* Full frame received */ #define FEC_ENET_RXF_2 ((uint)0x00000020) /* Full frame received */ +#endif #define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ #define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ #define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ @@ -380,6 +402,7 @@ struct bufdesc_ex { #define FEC_ENET_TS_TIMER ((uint)0x00008000) #define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF) +#define FEC_NAPI_IMASK FEC_ENET_MII #define FEC_RX_DISABLED_IMASK (FEC_DEFAULT_IMASK & (~FEC_ENET_RXF)) /* ENET interrupt coalescing macro define */ @@ -587,9 +610,25 @@ struct fec_enet_private { int pps_enable; unsigned int next_counter; + /* More Than IP L2 switch */ + void __iomem *hwpsw; + bool l2switch; + u64 ethtool_stats[]; }; +/* L2 switch */ +#define L2SW_CTRL_REG_OFFSET (0x4) +/* Get proper base address for either L2 switch or MAC ENET */ +static inline void __iomem *fec_hwp(struct fec_enet_private *fep) +{ +#ifdef CONFIG_NET_DSA_MTIP_L2SW + if (fep->l2switch) + return fep->hwpsw; +#endif + return fep->hwp; +} + void fec_ptp_init(struct platform_device *pdev, int irq_idx); void fec_ptp_stop(struct platform_device *pdev); void fec_ptp_start_cyclecounter(struct net_device *ndev); diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index bd29c84fd89a..32dbb1d18785 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -65,10 +65,12 @@ #include #include #include +#include #include #include "fec.h" +#include "../../dsa/mtip-l2switch.h" static void set_multicast_list(struct net_device *ndev); static void fec_enet_itr_coal_init(struct net_device *ndev); @@ -103,6 +105,11 @@ static const struct fec_devinfo fec_imx28_info = { FEC_QUIRK_HAS_FRREG, }; +static const struct fec_devinfo fec_imx28l2sw_info = { + .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME | + FEC_QUIRK_SINGLE_MDIO | FEC_QUIRK_HAS_FRREG, +}; + static const struct fec_devinfo fec_imx6q_info = { .quirks = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | @@ -144,6 +151,9 @@ static struct platform_device_id fec_devtype[] = { }, { .name = "imx28-fec", .driver_data = (kernel_ulong_t)&fec_imx28_info, + }, { + .name = "imx28-l2switch", + .driver_data = (kernel_ulong_t)&fec_imx28l2sw_info, }, { .name = "imx6q-fec", .driver_data = (kernel_ulong_t)&fec_imx6q_info, @@ -166,6 +176,7 @@ enum imx_fec_type { IMX25_FEC = 1, /* runs on i.mx25/50/53 */ IMX27_FEC, /* runs on i.mx27/35/51 */ IMX28_FEC, + IMX28_L2SWITCH, IMX6Q_FEC, MVF600_FEC, IMX6SX_FEC, @@ -176,6 +187,8 @@ static const struct of_device_id fec_dt_ids[] = { { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], }, { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], }, { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], }, + { .compatible = "fsl,imx28-l2switch", + .data = &fec_devtype[IMX28_L2SWITCH], }, { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], }, { .compatible = "fsl,mvf600-fec", .data = &fec_devtype[MVF600_FEC], }, { .compatible = "fsl,imx6sx-fec", .data = &fec_devtype[IMX6SX_FEC], }, @@ -893,7 +906,7 @@ static void fec_enet_enable_ring(struct net_device *ndev) for (i = 0; i < fep->num_rx_queues; i++) { rxq = fep->rx_queue[i]; - writel(rxq->bd.dma, fep->hwp + FEC_R_DES_START(i)); + writel(rxq->bd.dma, fec_hwp(fep) + FEC_R_DES_START(i)); writel(PKT_MAXBUF_SIZE, fep->hwp + FEC_R_BUFF_SIZE(i)); /* enable DMA1/2 */ @@ -904,7 +917,7 @@ static void fec_enet_enable_ring(struct net_device *ndev) for (i = 0; i < fep->num_tx_queues; i++) { txq = fep->tx_queue[i]; - writel(txq->bd.dma, fep->hwp + FEC_X_DES_START(i)); + writel(txq->bd.dma, fec_hwp(fep) + FEC_X_DES_START(i)); /* enable DMA1/2 */ if (i) @@ -1078,6 +1091,29 @@ fec_restart(struct net_device *ndev) } #endif /* !defined(CONFIG_M5272) */ + if (fep->l2switch) { + /* + * Set PROMISC mode for MAC0/1 - it is necessary for L2 switch + * correct operation. + */ + rcntl |= MCF_FEC_RCR_PROM; + + /* + * In fec_restart, the FEC_R_CNTRL register is only configured + * for MAC0 controller (when 'mac1' DTS node is NOT enabled). + * + * For L2 switch we configure only one DTS node - 'eth_switch' + * so the same value shall be written to MAC1 corresponding + * register. + * + * The port configuration is finished in the DSA's 'link_adjust' + * callback - which also modifies FEC_R_CNTRL register to set + * proper link speed. + */ + writel(rcntl, + fep->hwp + ENET_L2_SW_PORT1_OFFSET + FEC_R_CNTRL); + } + writel(rcntl, fep->hwp + FEC_R_CNTRL); /* Setup multicast filter. */ @@ -1109,8 +1145,12 @@ fec_restart(struct net_device *ndev) if (fep->bufdesc_ex) fec_ptp_start_cyclecounter(ndev); - /* Enable interrupts we wish to service */ - if (fep->link) + /* + * Enable interrupts we wish to service - for L2 switch only + * MII interrupts are required for MAC{01} to allow proper + * PHY configuration. + */ + if (!fep->l2switch && fep->link) writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); else writel(0, fep->hwp + FEC_IMASK); @@ -1407,7 +1447,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) unsigned short status; struct sk_buff *skb_new = NULL; struct sk_buff *skb; - ushort pkt_len; + ushort pkt_len, l2pl; __u8 *data; int pkt_received = 0; struct bufdesc_ex *ebdp = NULL; @@ -1433,7 +1473,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) break; pkt_received++; - writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); + writel(FEC_ENET_RXF, fec_hwp(fep) + FEC_IEVENT); /* Check for errors. */ status ^= BD_ENET_RX_LAST; @@ -1473,7 +1513,16 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) * include that when passing upstream as it messes up * bridging applications. */ - is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, pkt_len - 4, + /* + * When the L2 switch support is enabled the FCS is removed + * by it and hence the pkt_len shall be passed without + * substracting 4 bytes. + */ + l2pl = pkt_len - 4; + if (fep->l2switch) + l2pl = pkt_len; + + is_copybreak = fec_enet_copybreak(ndev, &skb, bdp, l2pl, need_swap); if (!is_copybreak) { skb_new = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); @@ -1488,7 +1537,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) } prefetch(skb->data - NET_IP_ALIGN); - skb_put(skb, pkt_len - 4); + skb_put(skb, l2pl); data = skb->data; if (!is_copybreak && need_swap) @@ -1605,12 +1654,12 @@ static bool fec_enet_collect_events(struct fec_enet_private *fep) { uint int_events; - int_events = readl(fep->hwp + FEC_IEVENT); + int_events = readl(fec_hwp(fep) + FEC_IEVENT); /* Don't clear MDIO events, we poll for those */ int_events &= ~FEC_ENET_MII; - writel(int_events, fep->hwp + FEC_IEVENT); + writel(int_events, fec_hwp(fep) + FEC_IEVENT); return int_events != 0; } @@ -1635,6 +1684,27 @@ fec_enet_interrupt(int irq, void *dev_id) return ret; } +#ifdef CONFIG_NET_DSA_MTIP_L2SW +static irqreturn_t +l2switch_interrupt_handler(int irq, void *dev_id) +{ + struct net_device *ndev = dev_id; + struct fec_enet_private *fep = netdev_priv(ndev); + irqreturn_t ret = IRQ_NONE; + + if (fec_enet_collect_events(fep) && fep->link) { + ret = IRQ_HANDLED; + + if (napi_schedule_prep(&fep->napi)) { + /* Disable NAPI interrupts */ + writel(0, fep->hwpsw + FEC_IMASK); + __napi_schedule(&fep->napi); + } + } + return ret; +} +#endif + static int fec_enet_rx_napi(struct napi_struct *napi, int budget) { struct net_device *ndev = napi->dev; @@ -1648,7 +1718,7 @@ static int fec_enet_rx_napi(struct napi_struct *napi, int budget) if (done < budget) { napi_complete_done(napi, done); - writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); + writel(FEC_DEFAULT_IMASK, fec_hwp(fep) + FEC_IMASK); } return done; @@ -3065,6 +3135,10 @@ static void set_multicast_list(struct net_device *ndev) unsigned char hash; unsigned int hash_high = 0, hash_low = 0; + /* DSA subsystem will handle multicast/broadcast setup for L2 switch */ + if (fep->l2switch) + return; + if (ndev->flags & IFF_PROMISC) { tmp = readl(fep->hwp + FEC_R_CNTRL); tmp |= 0x8; @@ -3279,7 +3353,8 @@ static int fec_enet_init(struct net_device *ndev) rxq->bd.dma = bd_dma; rxq->bd.dsize = dsize; rxq->bd.dsize_log2 = dsize_log2; - rxq->bd.reg_desc_active = fep->hwp + offset_des_active_rxq[i]; + rxq->bd.reg_desc_active = + fec_hwp(fep) + offset_des_active_rxq[i]; bd_dma += size; cbd_base = (struct bufdesc *)(((void *)cbd_base) + size); rxq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize); @@ -3295,7 +3370,8 @@ static int fec_enet_init(struct net_device *ndev) txq->bd.dma = bd_dma; txq->bd.dsize = dsize; txq->bd.dsize_log2 = dsize_log2; - txq->bd.reg_desc_active = fep->hwp + offset_des_active_txq[i]; + txq->bd.reg_desc_active = + fec_hwp(fep) + offset_des_active_txq[i]; bd_dma += size; cbd_base = (struct bufdesc *)(((void *)cbd_base) + size); txq->bd.last = (struct bufdesc *)(((void *)cbd_base) - dsize); @@ -3306,8 +3382,7 @@ static int fec_enet_init(struct net_device *ndev) ndev->watchdog_timeo = TX_TIMEOUT; ndev->netdev_ops = &fec_netdev_ops; ndev->ethtool_ops = &fec_enet_ethtool_ops; - - writel(FEC_RX_DISABLED_IMASK, fep->hwp + FEC_IMASK); + writel(FEC_RX_DISABLED_IMASK, fec_hwp(fep) + FEC_IMASK); netif_napi_add(ndev, &fep->napi, fec_enet_rx_napi, NAPI_POLL_WEIGHT); if (fep->quirks & FEC_QUIRK_HAS_VLAN) @@ -3544,6 +3619,23 @@ fec_probe(struct platform_device *pdev) fep->pdev = pdev; fep->dev_id = dev_id++; + if (of_device_is_compatible(np, "fsl,imx28-l2switch")) { + fep->l2switch = true; + fep->hwpsw = devm_platform_ioremap_resource(pdev, 1); + /* + * MAC{01} interrupt and descriptors registers have 4 bytes + * offset when compared to L2 switch IP block. + * + * When L2 switch is added "between" ENET (eth0) and MAC{01} + * the code for interrupts and setting up descriptors is + * reused. + * + * As for example FEC_IMASK are used also on MAC{01} to + * perform MII transmission it is better to subtract the + * offset from the outset and reuse defines. + */ + fep->hwpsw -= L2SW_CTRL_REG_OFFSET; + } platform_set_drvdata(pdev, ndev); if ((of_machine_is_compatible("fsl,imx6q") || @@ -3669,8 +3761,16 @@ fec_probe(struct platform_device *pdev) ret = irq; goto failed_irq; } - ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt, - 0, pdev->name, ndev); +#ifdef CONFIG_NET_DSA_MTIP_L2SW + if (fep->l2switch && i == 0) + ret = devm_request_irq(&pdev->dev, irq, + l2switch_interrupt_handler, + 0, "l2switch", ndev); + else +#endif + ret = devm_request_irq(&pdev->dev, irq, + fec_enet_interrupt, + 0, pdev->name, ndev); if (ret) goto failed_irq; @@ -3683,7 +3783,16 @@ fec_probe(struct platform_device *pdev) /* Carrier starts down, phylib will bring it up */ netif_carrier_off(ndev); - fec_enet_clk_enable(ndev, false); + /* + * For L2 switch proper initialization this clk cannot be disabled, + * as it uses is to access shared MAC registers for proper MDIO + * operation. + * + * DSA switch will also use it afterwards to setup its ports. + */ + if (!fep->l2switch) + fec_enet_clk_enable(ndev, false); + pinctrl_pm_select_sleep_state(&pdev->dev); ndev->max_mtu = PKT_MAXBUF_SIZE - ETH_HLEN - ETH_FCS_LEN; From patchwork Wed Nov 25 23:24:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukasz Majewski X-Patchwork-Id: 11932353 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 X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id ED2C7C64E7D for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C49E920872 for ; Wed, 25 Nov 2020 23:26:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733241AbgKYXZ6 (ORCPT ); Wed, 25 Nov 2020 18:25:58 -0500 Received: from mail-out.m-online.net ([212.18.0.9]:37252 "EHLO mail-out.m-online.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731750AbgKYXZ4 (ORCPT ); Wed, 25 Nov 2020 18:25:56 -0500 Received: from frontend01.mail.m-online.net (unknown [192.168.8.182]) by mail-out.m-online.net (Postfix) with ESMTP id 4ChH7k2VYrz1qs3D; Thu, 26 Nov 2020 00:25:54 +0100 (CET) Received: from localhost (dynscan1.mnet-online.de [192.168.6.70]) by mail.m-online.net (Postfix) with ESMTP id 4ChH7k27VHz1vdfr; Thu, 26 Nov 2020 00:25:54 +0100 (CET) X-Virus-Scanned: amavisd-new at mnet-online.de Received: from mail.mnet-online.de ([192.168.8.182]) by localhost (dynscan1.mail.m-online.net [192.168.6.70]) (amavisd-new, port 10024) with ESMTP id xsV1O1AGOiez; Thu, 26 Nov 2020 00:25:52 +0100 (CET) X-Auth-Info: bSbI5zVU0PcFVOfLl5E/cpCrEQQdaQoXBldrUCwgHoo= Received: from localhost.localdomain (89-64-5-98.dynamic.chello.pl [89.64.5.98]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.mnet-online.de (Postfix) with ESMTPSA; Thu, 26 Nov 2020 00:25:52 +0100 (CET) From: Lukasz Majewski To: Fugang Duan , "David S . Miller" , Jakub Kicinski , netdev@vger.kernel.org, Andrew Lunn , Fabio Estevam , Vivien Didelot Cc: NXP Linux Team , Florian Fainelli , Vladimir Oltean , linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, Peng Fan , stefan.agner@toradex.com, krzk@kernel.org, Shawn Guo , Lukasz Majewski Subject: [RFC 4/4] ARM: dts: imx28: Add description for L2 switch on XEA board Date: Thu, 26 Nov 2020 00:24:59 +0100 Message-Id: <20201125232459.378-5-lukma@denx.de> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20201125232459.378-1-lukma@denx.de> References: <20201125232459.378-1-lukma@denx.de> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-State: RFC The 'eth_switch' node is now used to enable support for L2 switch. Moreover, a separate 'switch' node was introduced to keep the code more clean. Signed-off-by: Lukasz Majewski --- arch/arm/boot/dts/imx28-xea.dts | 55 +++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/arch/arm/boot/dts/imx28-xea.dts b/arch/arm/boot/dts/imx28-xea.dts index 672080485b78..b8a896df02c0 100644 --- a/arch/arm/boot/dts/imx28-xea.dts +++ b/arch/arm/boot/dts/imx28-xea.dts @@ -9,6 +9,30 @@ / { model = "XEA"; + + switch { + compatible = "imx,mtip-l2switch"; + reg = <0x800f8000 0x400>, <0x800fC000 0x4000>; + ports { + port0@0 { + reg = <0>; + label = "lan1"; + phy-handle = <ðsw0>; + }; + + port1@1 { + reg = <1>; + label = "lan2"; + phy-handle = <ðsw1>; + }; + + port2@2 { + reg = <2>; + label = "cpu"; + ethernet = <ð_switch>; + }; + }; + }; }; &can0 { @@ -23,6 +47,37 @@ status = "okay"; }; +ð_switch { + compatible = "fsl,imx28-l2switch"; + reg = <0x800f0000 0x8000>, <0x800f8400 0x400>; + pinctrl-names = "default"; + pinctrl-0 = <&mac0_pins_a>, <&mac1_pins_a>; + phy-mode = "rmii"; + phy-supply = <®_fec_3v3>; + phy-reset-gpios = <&gpio2 13 0>; + phy-reset-duration = <100>; + interrupts = <100>, <101>, <102>; + clocks = <&clks 57>, <&clks 57>, <&clks 64>, <&clks 35>; + clock-names = "ipg", "ahb", "enet_out", "ptp"; + local-mac-address = [ 00 11 22 AA BB CC ]; + status = "okay"; + + fixed-link { + speed = <100>; + full-duplex; + }; + + mdio { + ethsw0: ethernet-phy@0 { + reg = <0>; + }; + + ethsw1: ethernet-phy@1 { + reg = <1>; + }; + }; +}; + &pinctrl { pinctrl-names = "default"; pinctrl-0 = <&hog_pins_a &hog_pins_tiva>;