diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2022-08-14 00:45:54 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:38:43 +0300 |
| commit | 8a50c618aa50996e4f7f588d9372f379435af1d9 (patch) | |
| tree | 0a12034add387a26bf1fd24a7693571d9f8ec415 | |
| parent | a20299db9d8b967f2bca4fc2bcfa0f173d331ac4 (diff) | |
| download | linux-xgmac/bt1.tar.gz linux-xgmac/bt1.zip | |
net: stmmac: Add Baikal-T1 GMAC/XGMAC supportxgmac/bt1
Baikal-T1 is equipped with two DW GMAC v3.73a controllers synthesized with
RGMII interface, MDIO bus, 16KB MTL Rx/Tx FIFO, 8 MAC address perfect
filter slots, HW-based SA/VLAN/CRC insertion, 1xGPO and 1xGPI, EEE logic,
IEEE 1588 Timestamping with Advanced capabilities, PMT capability with
MagicPacket and Remote Wake-up support, Full Tx/Rx CSUM, IPv4 ARP offload,
no hash-table and no L3/L4 filter logic. In addition to that there is DW
XGMAC v2.11a and DW XPCS 3.11b synthesized with 10GBase-KR and 10GBase-KX4
physical interface, no MDIO bus, 32KB MTL Rx/Tx FIFO, 8 MAC address
perfect filter slots, 64 slot in the Hash-based DA filter, VLAN Hash-based
filter, 2x L3/L4 filters, 2x TCs, 2x Tx MTL Queues, 4x Rx MTL Queues, DCB
feature, TSO and SPH for TCP/IP packets, Full Tx/Rx CSUM Offload, IPv4 ARP
offload, 64-entries RSS table, IEEE 1588 Timestamping with Advanced
capabilities, no PMT.
Most of that is more-or-less supported by the STMMAC driver. The only
thing left to do is to add the Baikal-T1 platform-specific glue driver for
it.
The LLDD is mainly responsible for the standard STMMAC driver
pre-initialization and the platform device probing. There are some
peculiar Baikal-T1 GMAC-specific actions performed aside of that though.
First of all we need to enable/disable the RGMII Tx clock and tune its
rate up based on the RGMII interface mode. Secondly due to the having the
most of the Baikal-T1 platforms using the embedded GPO for the attached
PHYs reset we have to make sure the DW GMAC core isn't reset after the
device is probed otherwise any PHY initializations performed afterwards
will be lost. In order to do that the custom DW GMAC software reset
callback is introduced. Finally for the same reason we've added a custom
MDIO bus reset method so the GPO would be set to a mainly valid value
before the platform Ethernet PHYs are actually probed.
Note the custom MDIO/COre reset methods is a temporary solution until we
get to clean the STMMAC driver up and introduce a fully generic GPIO
interface for the driver core.
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/Kconfig | 9 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/Makefile | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-bt1.c | 227 |
3 files changed, 237 insertions, 0 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 71c1a21ba969..9d8c9347893f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -70,6 +70,15 @@ config DWMAC_ANARION This selects the Anarion SoC glue layer support for the stmmac driver. +config DWMAC_BT1 + tristate "Baikal-T1 GMAC/xGMAC support" + depends on OF && (MIPS_BAIKAL_T1 || COMPILE_TEST) + help + Support for Baikal-T1 (x)GMAC Ethernet controller. + + This selects the Baikal-T1 platform specific glue layer of the + STMMAC driver. + config DWMAC_EIC7700 tristate "Support for Eswin eic7700 ethernet driver" depends on OF && HAS_DMA && ARCH_ESWIN || COMPILE_TEST diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index cd3c62b4a964..a63522ee0b38 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -14,6 +14,7 @@ stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o # Ordering matters. Generic driver must be last. obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o obj-$(CONFIG_DWMAC_ANARION) += dwmac-anarion.o +obj-$(CONFIG_DWMAC_BT1) += dwmac-bt1.o obj-$(CONFIG_DWMAC_EIC7700) += dwmac-eic7700.o obj-$(CONFIG_DWMAC_INGENIC) += dwmac-ingenic.o obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-bt1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-bt1.c new file mode 100644 index 000000000000..d14b233d13c2 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-bt1.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Baikal-T1 GMAC driver + * + * Copyright (C) 2022 BAIKAL ELECTRONICS, JSC + */ +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pcs/pcs-xpcs.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <linux/sizes.h> +#include <linux/slab.h> + +#include "stmmac.h" +#include "stmmac_platform.h" + +struct bt1_xgmac { + struct device *dev; +}; + +typedef int (*bt1_xgmac_plat_init)(struct bt1_xgmac *, struct plat_stmmacenet_data *); + +static void bt1_gmac_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, + unsigned long *interfaces) +{ + phy_interface_set_rgmii(interfaces); +} + +static int bt1_gmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) +{ + long rate; + int ret; + + if (!phy_interface_mode_is_rgmii(interface)) + return -EINVAL; + + rate = rgmii_clock(speed); + if (rate < 0) + return -EINVAL; + + /* Tx clock must be gated to successfully update the rate */ + clk_disable_unprepare(clk_tx_i); + + /* Clock is running with double rate (5 MHz, 50 MHz and 250 MHz) */ + ret = clk_set_rate(clk_tx_i, 2 * rate); + if (ret) + goto err_en_clk; + + return clk_prepare_enable(clk_tx_i); + +err_en_clk: + clk_prepare_enable(clk_tx_i); + + return ret; +} + +static int bt1_gmac_plat_data_init(struct bt1_xgmac *btxg, + struct plat_stmmacenet_data *plat) +{ + phy_interface_t interface; + int phyif; + + plat->core_type = DWMAC_CORE_GMAC; + plat->host_dma_width = 32; + plat->tx_fifo_size = SZ_16K; + plat->rx_fifo_size = SZ_16K; + plat->enh_desc = 1; + plat->tx_coe = 1; + plat->rx_coe = 1; + plat->pmt = 1; + plat->unicast_filter_entries = 8; + plat->multicast_filter_bins = 0; + plat->set_clk_tx_rate = bt1_gmac_set_clk_tx_rate; + plat->get_interfaces = bt1_gmac_get_interfaces; + plat->mdio_bus_data->needs_reset = true; + plat->ngpios = 2; + + phyif = stmmac_get_phy_intf_sel(plat->phy_interface); + if (phyif != PHY_INTF_SEL_RGMII) { + dev_err(btxg->dev, "Unsupported PHY interface specified\n"); + return -EINVAL; + } + + interface = phy_fix_phy_mode_for_mac_delays(plat->phy_interface, true, false); + if (interface == PHY_INTERFACE_MODE_NA) { + dev_err(btxg->dev, "Unsupported RGMII mode specified\n"); + return -EINVAL; + } + + plat->phy_interface = interface; + + return 0; +} + +static void bt1_xgmac_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, + unsigned long *interfaces) +{ + __set_bit(PHY_INTERFACE_MODE_XGMII, interfaces); + __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces); + __set_bit(PHY_INTERFACE_MODE_10GBASEX, interfaces); + __set_bit(PHY_INTERFACE_MODE_XAUI, interfaces); +} + +static struct phylink_pcs *bt1_xgmac_select_pcs(struct stmmac_priv *priv, + phy_interface_t interface) +{ + return xpcs_to_phylink_pcs(priv->hw->xpcs); +} + +static int bt1_xgmac_plat_data_init(struct bt1_xgmac *btxg, + struct plat_stmmacenet_data *plat) +{ + /* Note Disabling SPH improves the network performance for about + * 300Mbit/s. Might be due to the DMA-syncing for two buffers. + * Also SPH consumes twice the normal memory especially if there + * is a single page-per-buffer allocated. + */ + plat->core_type = DWMAC_CORE_XGMAC; + plat->host_dma_width = 40; + plat->tx_fifo_size = SZ_32K; + plat->rx_fifo_size = SZ_32K; + plat->tx_coe = 1; + plat->rx_coe = 1; + plat->rss_en = 1; /* & cap.rssen */ + plat->unicast_filter_entries = 8; + plat->multicast_filter_bins = 64; + plat->select_pcs = bt1_xgmac_select_pcs; + plat->get_interfaces = bt1_xgmac_get_interfaces; + plat->flags |= STMMAC_FLAG_TSO_EN | /* & cap.tsoen */ + STMMAC_FLAG_TSO_FULL | /* all channels TSO-capable */ + STMMAC_FLAG_SPH_DISABLE | /* & cap.sph */ + STMMAC_FLAG_MULTI_MSI_EN; + + /* Attached XPCS supports 10GBase-KR/KX4 modes */ + switch (plat->phy_interface) { + case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_10GBASEX: + case PHY_INTERFACE_MODE_XAUI: + break; + default: + dev_err(btxg->dev, "Unsupported PHY interface specified\n"); + return -EINVAL; + } + + return 0; +} + +static int bt1_xgmac_data_init(struct platform_device *pdev, + struct plat_stmmacenet_data *plat) +{ + bt1_xgmac_plat_init plat_init; + struct bt1_xgmac *btxg; + int ret; + + btxg = devm_kzalloc(&pdev->dev, sizeof(*btxg), GFP_KERNEL); + if (!btxg) + return -ENOMEM; + + btxg->dev = &pdev->dev; + + plat->bsp_priv = btxg; + plat->clk_tx_i = devm_clk_get_enabled(&pdev->dev, "tx"); + if (IS_ERR(plat->clk_tx_i)) + return dev_err_probe(&pdev->dev, PTR_ERR(plat->clk_tx_i), + "Failed to get tx clock\n"); + + plat_init = device_get_match_data(&pdev->dev); + if (plat_init) { + ret = plat_init(btxg, plat); + if (ret) + return ret; + } + + return 0; +} + +static int bt1_xgmac_probe(struct platform_device *pdev) +{ + struct stmmac_resources stmmac_res; + struct plat_stmmacenet_data *plat; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR(plat)) + return dev_err_probe(&pdev->dev, PTR_ERR(plat), "DT config failed\n"); + + ret = bt1_xgmac_data_init(pdev, plat); + if (ret) + return ret; + + ret = devm_stmmac_pltfr_probe(pdev, plat, &stmmac_res); + if (ret) + return ret; + + return 0; +} + +static const struct of_device_id bt1_xgmac_match[] = { + { .compatible = "baikal,bt1-gmac", .data = (void *)bt1_gmac_plat_data_init }, + { .compatible = "baikal,bt1-xgmac", .data = (void *)bt1_xgmac_plat_data_init }, + { } +}; +MODULE_DEVICE_TABLE(of, bt1_xgmac_match); + +static struct platform_driver bt1_xgmac_driver = { + .probe = bt1_xgmac_probe, + .driver = { + .name = "bt1-xgmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = of_match_ptr(bt1_xgmac_match), + }, +}; +module_platform_driver(bt1_xgmac_driver); + +MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); +MODULE_DESCRIPTION("Baikal-T1 GMAC/XGMAC glue driver"); +MODULE_LICENSE("GPL v2"); |
