From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on sa.local.altlinux.org X-Spam-Level: X-Spam-Status: No, score=-4.3 required=5.0 tests=ALL_TRUSTED,BAYES_00, RP_MATCHES_RCVD autolearn=ham autolearn_force=no version=3.4.1 From: Daniil Gnusarev To: devel-kernel@lists.altlinux.org Date: Mon, 14 Oct 2024 18:01:51 +0400 Message-ID: <20241014140221.535985-11-gnusarevda@basealt.ru> X-Mailer: git-send-email 2.42.2 In-Reply-To: <20241014140221.535985-1-gnusarevda@basealt.ru> References: <20241014140221.535985-1-gnusarevda@basealt.ru> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: [d-kernel] [PATCH 10/39] net: stmmac: support of Baikal-BE1000 SoCs GMAC X-BeenThere: devel-kernel@lists.altlinux.org X-Mailman-Version: 2.1.12 Precedence: list Reply-To: ALT Linux kernel packages development List-Id: ALT Linux kernel packages development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Oct 2024 14:02:09 -0000 Archived-At: List-Archive: List-Post: The Gigabit Ethernet Controller available in the Baikal-M SoC is a Synopsys DesignWare MAC IP core, already supported by the stmmac driver. This add Baikal Electronics DWMAC specific glue layer. Signed-off-by: Daniil Gnusarev Co-developed-by: Dmitry Dunaev Co-developed-by: Alexey Sheplyakov --- drivers/net/ethernet/stmicro/stmmac/Kconfig | 8 + drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + .../ethernet/stmicro/stmmac/dwmac-baikal.c | 542 ++++++++++++++++++ .../ethernet/stmicro/stmmac/dwmac1000_core.c | 1 + .../ethernet/stmicro/stmmac/dwmac1000_dma.c | 56 +- .../ethernet/stmicro/stmmac/dwmac1000_dma.h | 32 ++ .../net/ethernet/stmicro/stmmac/dwmac_lib.c | 8 + net/ethernet/eth.c | 1 + 8 files changed, 626 insertions(+), 23 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 92d7d5a00b84c..34ea1d065fb72 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -66,6 +66,14 @@ config DWMAC_ANARION This selects the Anarion SoC glue layer support for the stmmac driver. +config DWMAC_BAIKAL + tristate "Baikal Electronics DWMAC support" + depends on OF + help + Support for Baikal Electronics DWMAC Ethernet. + + This selects the Baikal SoC glue layer support for the stmmac driver. + config DWMAC_INGENIC tristate "Ingenic MAC support" default MACH_INGENIC diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 5b57aee19267f..7c39c5a4b4d6f 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_BAIKAL) += dwmac-baikal.o obj-$(CONFIG_DWMAC_INGENIC) += dwmac-ingenic.o obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c new file mode 100644 index 0000000000000..a9a66068b3f65 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c @@ -0,0 +1,542 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Baikal Electronics DWMAC specific glue layer + * + * Copyright (C) 2015-2022 Baikal Electronics, JSC + * Authors: Dmitry Dunaev + * Alexey Sheplyakov + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac.h" +#include "stmmac_platform.h" +#include "common.h" +#include "dwmac_dma.h" +#include "dwmac1000_dma.h" + +#define MAC_GPIO 0x00e0 /* GPIO register */ +#define MAC_GPIO_GPO (1 << 8) /* Output port */ + +#define BAIKAL_SMC_GMAC_DIV2_ENABLE 0xC2000500 +#define BAIKAL_SMC_GMAC_DIV2_DISABLE 0xC2000501 + +struct baikal_gmac { + struct device *dev; + uint64_t base; + struct clk *axi_clk; + struct clk *tx2_clk; + int has_aux_div2; + bool is_fixed_stmmac_clk; +}; + +static int baikal_gmac_dma_reset(void __iomem *ioaddr) +{ + int err; + u32 value; + + /* DMA SW reset */ + value = readl(ioaddr + DMA_BUS_MODE); + value |= DMA_BUS_MODE_SFT_RESET; + writel(value, ioaddr + DMA_BUS_MODE); + + /* Software DMA reset also resets MAC, so GP_OUT is set to zero. + * Which resets PHY as a side effect (if GP_OUT is connected directly + * to PHY reset). + * TODO: read the PHY reset duration from the device tree. + * Meanwhile use 100 milliseconds which seems to be enough for + * most PHYs + */ + usleep_range(100000, 120000); + + /* Clear PHY reset */ + value = readl(ioaddr + MAC_GPIO); + value |= MAC_GPIO_GPO; + writel(value, ioaddr + MAC_GPIO); + + /* Many PHYs need ~100 milliseconds to calm down after PHY reset + * has been cleared. And check for DMA reset below might return + * much earlier (i.e. in ~20 milliseconds). As a result reading + * PHY registers (after this function returns) might return garbage. + * Wait a bit to avoid the problem. + */ + usleep_range(100000, 150000); + + err = readl_poll_timeout(ioaddr + DMA_BUS_MODE, value, + !(value & DMA_BUS_MODE_SFT_RESET), + 10000, 1000000); + if (err) { + return -EBUSY; + } + + return 0; +} + +static const struct stmmac_dma_ops baikal_gmac_dma_ops = { + .reset = baikal_gmac_dma_reset, + .init = dwmac1000_dma_init, + .init_rx_chan = dwmac1000_dma_init_rx, + .init_tx_chan = dwmac1000_dma_init_tx, + .axi = dwmac1000_dma_axi, + .dump_regs = dwmac1000_dump_dma_regs, + .dma_rx_mode = dwmac1000_dma_operation_mode_rx, + .dma_tx_mode = dwmac1000_dma_operation_mode_tx, + .enable_dma_transmission = dwmac_enable_dma_transmission, + .enable_dma_irq = dwmac_enable_dma_irq, + .disable_dma_irq = dwmac_disable_dma_irq, + .start_tx = dwmac_dma_start_tx, + .stop_tx = dwmac_dma_stop_tx, + .start_rx = dwmac_dma_start_rx, + .stop_rx = dwmac_dma_stop_rx, + .dma_interrupt = dwmac_dma_interrupt, + .get_hw_feature = dwmac1000_get_hw_feature, + .rx_watchdog = dwmac1000_rx_watchdog +}; + +static struct mac_device_info *baikal_gmac_setup(void *ppriv) +{ + struct mac_device_info *mac, *old_mac; + struct stmmac_priv *priv = ppriv; + struct gpio_desc *reset_gpio; + int err; + u32 value; + + mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); + if (!mac) { + return NULL; + } + + /* Clear PHY reset */ + value = readl(priv->ioaddr + MAC_GPIO); + value |= MAC_GPIO_GPO; + writel(value, priv->ioaddr + MAC_GPIO); + reset_gpio = devm_gpiod_get_optional(priv->device, + "snps,reset", + GPIOD_OUT_LOW); + + err = readl_poll_timeout(priv->ioaddr + DMA_BUS_MODE, value, + !(value & DMA_BUS_MODE_SFT_RESET), + 10000, 1000000); + + if (reset_gpio != NULL) { + devm_gpiod_put(priv->device, reset_gpio); + } + + if (err) { + dev_err(priv->device, "SW reset is not cleared: error %d", err); + return NULL; + } + + mac->dma = &baikal_gmac_dma_ops; + old_mac = priv->hw; + priv->hw = mac; + err = dwmac1000_setup(priv); + priv->hw = old_mac; + if (err) { + dev_err(priv->device, + "%s: dwmac1000_setup failed with error %d", + __func__, err); + return NULL; + } + + return mac; +} + +static void baikal_gmac_fix_mac_speed(void *priv, unsigned int speed, + unsigned int mode) +{ + struct arm_smccc_res res; + struct baikal_gmac *gmac = priv; + unsigned long tx2_clk_freq = 0; + + switch (speed) { + case SPEED_1000: + tx2_clk_freq = 250000000; + if (gmac->has_aux_div2) { + arm_smccc_smc(BAIKAL_SMC_GMAC_DIV2_DISABLE, + gmac->base, 0, 0, 0, 0, 0, 0, &res); + } + break; + case SPEED_100: + tx2_clk_freq = 50000000; + if (gmac->has_aux_div2) { + arm_smccc_smc(BAIKAL_SMC_GMAC_DIV2_DISABLE, + gmac->base, 0, 0, 0, 0, 0, 0, &res); + } + break; + case SPEED_10: + tx2_clk_freq = 5000000; + if (gmac->has_aux_div2) { + tx2_clk_freq *= 2; + arm_smccc_smc(BAIKAL_SMC_GMAC_DIV2_ENABLE, + gmac->base, 0, 0, 0, 0, 0, 0, &res); + } + break; + } + + if (gmac->tx2_clk != NULL && tx2_clk_freq) { + clk_set_rate(gmac->tx2_clk, tx2_clk_freq); + } +} + +#ifdef CONFIG_ACPI +static struct plat_stmmacenet_data *baikal_stmmac_probe_config(struct device *dev, + const char **mac, + bool *is_fixed_stmmac_clk) +{ + struct plat_stmmacenet_data *plat_dat; + u8 nvmem_mac[ETH_ALEN]; + int ret; + bool is_fixed_clk = false; + + plat_dat = devm_kzalloc(dev, sizeof(*plat_dat), GFP_KERNEL); + if (!plat_dat) { + return ERR_PTR(-ENOMEM); + } + + ret = nvmem_get_mac_address(dev, &nvmem_mac); + if (ret) { + if (ret == -EPROBE_DEFER) { + return ERR_PTR(ret); + } + + *mac = NULL; + } else { + *mac = devm_kmemdup(dev, nvmem_mac, ETH_ALEN, GFP_KERNEL); + } + + plat_dat->phy_interface = device_get_phy_mode(dev); + if (plat_dat->phy_interface < 0) { + return NULL; + } + + plat_dat->mac_interface = plat_dat->phy_interface; + + if (device_property_read_u32(dev, "max-speed", &plat_dat->max_speed)) { + plat_dat->max_speed = -1; + } + + plat_dat->bus_id = ACPI_COMPANION(dev)->pnp.instance_no; + + ret = device_property_read_u32(dev, "reg", &plat_dat->phy_addr); + if (ret) { + dev_err(dev, "couldn't get reg property\n"); + return ERR_PTR(ret); + } + + if (plat_dat->phy_addr >= PHY_MAX_ADDR) { + dev_err(dev, "PHY address %i is too large\n", + plat_dat->phy_addr); + return ERR_PTR(-EINVAL); + } + + plat_dat->mdio_bus_data = devm_kzalloc(dev, + sizeof(*plat_dat->mdio_bus_data), + GFP_KERNEL); + if (!plat_dat->mdio_bus_data) { + return ERR_PTR(-ENOMEM); + } + + plat_dat->mdio_bus_data->needs_reset = true; + plat_dat->maxmtu = JUMBO_LEN; + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + plat_dat->unicast_filter_entries = 1; + plat_dat->bugged_jumbo = 1; /* TODO: is it really required? */ + + plat_dat->dma_cfg = devm_kzalloc(dev, + sizeof(*plat_dat->dma_cfg), + GFP_KERNEL); + if (!plat_dat->dma_cfg) { + return ERR_PTR(-ENOMEM); + } + + plat_dat->dma_cfg->pbl = DEFAULT_DMA_PBL; + device_property_read_u32(dev, "snps,txpbl", &plat_dat->dma_cfg->txpbl); + device_property_read_u32(dev, "snps,rxpbl", &plat_dat->dma_cfg->rxpbl); + plat_dat->dma_cfg->fixed_burst = device_property_read_bool(dev, + "snps,fixed-burst"); + + plat_dat->axi = devm_kzalloc(dev, sizeof(*plat_dat->axi), GFP_KERNEL); + if (!plat_dat->axi) { + return ERR_PTR(-ENOMEM); + } + + device_property_read_u32_array(dev, "snps,blen", + plat_dat->axi->axi_blen, AXI_BLEN); + + plat_dat->rx_queues_to_use = 1; + plat_dat->tx_queues_to_use = 1; + plat_dat->rx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB; + plat_dat->tx_queues_cfg[0].mode_to_use = MTL_QUEUE_DCB; + + if (device_property_read_u32(dev, "stmmac-clk", &plat_dat->clk_ptp_rate)) { + plat_dat->clk_ptp_rate = 50000000; + } + + plat_dat->stmmac_clk = devm_clk_get(dev, STMMAC_RESOURCE_NAME); + if (IS_ERR(plat_dat->stmmac_clk)) { + if (!plat_dat->clk_ptp_rate) { + dev_err(dev, "stmmaceth clock and 'stmmac-clk' property are missed simultaneously\n"); + return ERR_PTR(-EINVAL); + } + + plat_dat->stmmac_clk = clk_register_fixed_rate(NULL, + dev_name(dev), NULL, 0, + plat_dat->clk_ptp_rate); + if (IS_ERR(plat_dat->stmmac_clk)) + return ERR_CAST(plat_dat->stmmac_clk); + + is_fixed_clk = true; + } else { + if (!plat_dat->clk_ptp_rate) + plat_dat->clk_ptp_rate = clk_get_rate(plat_dat->stmmac_clk); + } + + plat_dat->clk_ptp_ref = devm_clk_get(dev, "ptp_ref"); + if (IS_ERR(plat_dat->clk_ptp_ref)) { + plat_dat->clk_ptp_ref = NULL; + } else { + plat_dat->clk_ptp_rate = clk_get_rate(plat_dat->clk_ptp_ref); + } + + clk_prepare_enable(plat_dat->stmmac_clk); + + plat_dat->stmmac_rst = devm_reset_control_get(dev, + STMMAC_RESOURCE_NAME); + if (IS_ERR(plat_dat->stmmac_rst)) + plat_dat->stmmac_rst = NULL; + + plat_dat->mdio_bus_data->phy_mask = ~0; + + if (device_get_child_node_count(dev) != 1) { + clk_disable_unprepare(plat_dat->stmmac_clk); + if (is_fixed_clk) + clk_unregister_fixed_rate(plat_dat->stmmac_clk); + return ERR_PTR(-EINVAL); + } + + *is_fixed_stmmac_clk = is_fixed_clk; + + return plat_dat; +} + +static int baikal_add_mdio_phy(struct device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + struct fwnode_handle *fwnode = device_get_next_child_node(dev, NULL); + struct phy_device *phy; + int ret; + + phy = get_phy_device(priv->mii, priv->plat->phy_addr, 0); + if (IS_ERR(phy)) { + return PTR_ERR(phy); + } + + phy->irq = priv->mii->irq[priv->plat->phy_addr]; + phy->mdio.dev.fwnode = fwnode; + + ret = phy_device_register(phy); + if (ret) { + phy_device_free(phy); + return ret; + } + + return 0; +} +#else +static struct plat_stmmacenet_data *baikal_stmmac_probe_config(struct device *dev, + const char **mac, + bool *is_fixed_stmmac_clk) +{ + return NULL; +} + +static int baikal_add_mdio_phy(struct device *dev) +{ + return 0; +} +#endif + +static int baikal_gmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct resource *res; + struct baikal_gmac *gmac; + struct device_node *dn = NULL; + const char *str = NULL; + bool is_fixed_stmmac_clk = false; + int ret; + + if (acpi_disabled) { + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) { + return ret; + } + } else { + memset(&stmmac_res, 0, sizeof(stmmac_res)); + stmmac_res.irq = platform_get_irq(pdev, 0); + if (stmmac_res.irq < 0) { + return stmmac_res.irq; + } + + stmmac_res.wol_irq = stmmac_res.irq; + stmmac_res.addr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(stmmac_res.addr)) { + return PTR_ERR(stmmac_res.addr); + } + } + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_warn(&pdev->dev, "no suitable DMA available\n"); + return ret; + } + + if (pdev->dev.of_node) { + plat_dat = stmmac_probe_config_dt(pdev, (u8 *)&stmmac_res.mac); + if (IS_ERR(plat_dat)) { + dev_err(&pdev->dev, "dt configuration failed\n"); + return PTR_ERR(plat_dat); + } + } else if (!acpi_disabled) { + plat_dat = baikal_stmmac_probe_config(&pdev->dev, + (const char **)&stmmac_res.mac, + &is_fixed_stmmac_clk); + if (IS_ERR(plat_dat)) { + dev_err(&pdev->dev, "acpi configuration failed\n"); + return PTR_ERR(plat_dat); + } + + dn = kzalloc(sizeof(struct device_node), GFP_KERNEL); + if (!dn) { + ret = -ENOMEM; + goto err_remove_config_dt; + } + + plat_dat->phy_node = dn; + } else { + plat_dat = dev_get_platdata(&pdev->dev); + if (!plat_dat) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + /* Set default value for multicast hash bins */ + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat_dat->unicast_filter_entries = 1; + } + + gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL); + if (!gmac) { + ret = -ENOMEM; + goto err_remove_config_dt; + } + + gmac->dev = &pdev->dev; + gmac->tx2_clk = devm_clk_get(gmac->dev, "tx2_clk"); + if (IS_ERR(gmac->tx2_clk)) { + dev_warn(&pdev->dev, "couldn't get TX2 clock\n"); + gmac->tx2_clk = NULL; + } + + gmac->axi_clk = devm_clk_get(gmac->dev, "axi_clk"); + if (IS_ERR(gmac->axi_clk)) { + dev_warn(&pdev->dev, "couldn't get AXI clock\n"); + gmac->axi_clk = NULL; + } else { + clk_set_rate(gmac->axi_clk, 300000000); + } + + if (!acpi_disabled) { + device_property_read_string(&pdev->dev, "compatible", &str); + } + + if ((gmac->dev->of_node && + of_device_is_compatible(gmac->dev->of_node, "baikal,bs1000-gmac")) + || (str && strcasecmp(str, "baikal,bs1000-gmac") == 0)) { + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gmac->base = res->start; + gmac->has_aux_div2 = 1; + } else { + gmac->has_aux_div2 = 0; + } + + plat_dat->fix_mac_speed = baikal_gmac_fix_mac_speed; + plat_dat->bsp_priv = gmac; + plat_dat->has_gmac = 1; + plat_dat->bugged_jumbo = 1; /* TODO: is it really required? */ + plat_dat->setup = baikal_gmac_setup; + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) { + goto err_remove_config_dt; + } + + if (!acpi_disabled) { + ret = baikal_add_mdio_phy(&pdev->dev); + if (ret) { + goto err_remove_config_dt; + } + } + + gmac->is_fixed_stmmac_clk = is_fixed_stmmac_clk; + + kfree(dn); + return 0; + +err_remove_config_dt: + stmmac_remove_config_dt(pdev, plat_dat); + + if (is_fixed_stmmac_clk) + clk_unregister_fixed_rate(plat_dat->stmmac_clk); + + kfree(dn); + return ret; +} + +static void baikal_gmac_remove(struct platform_device *pdev) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(&pdev->dev)); + struct plat_stmmacenet_data *plat = priv->plat; + struct baikal_gmac *gmac = plat->bsp_priv; + + if (gmac->is_fixed_stmmac_clk) { + clk_disable_unprepare(plat->stmmac_clk); + clk_unregister_fixed_rate(plat->stmmac_clk); + plat->stmmac_clk = NULL; + } + + stmmac_pltfr_remove(pdev); +} + +static const struct of_device_id baikal_gmac_dwmac_match[] = { + { .compatible = "baikal,bm1000-gmac" }, + { .compatible = "baikal,bs1000-gmac" }, + { } +}; +MODULE_DEVICE_TABLE(of, baikal_gmac_dwmac_match); + +static struct platform_driver baikal_gmac_dwmac_driver = { + .probe = baikal_gmac_probe, + .remove_new = baikal_gmac_remove, + .driver = { + .name = "baikal-gmac-dwmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = of_match_ptr(baikal_gmac_dwmac_match) + } +}; +module_platform_driver(baikal_gmac_dwmac_driver); + +MODULE_DESCRIPTION("Baikal DWMAC specific glue driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 8555299443f4e..a047cedb74abb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -557,3 +557,4 @@ int dwmac1000_setup(struct stmmac_priv *priv) return 0; } +EXPORT_SYMBOL_GPL(dwmac1000_setup); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index daf79cdbd3ecf..1af8bb44034c0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -15,8 +15,9 @@ #include #include "dwmac1000.h" #include "dwmac_dma.h" +#include "dwmac1000_dma.h" -static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) +void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) { u32 value = readl(ioaddr + DMA_AXI_BUS_MODE); int i; @@ -69,9 +70,10 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) writel(value, ioaddr + DMA_AXI_BUS_MODE); } +EXPORT_SYMBOL_GPL(dwmac1000_dma_axi); -static void dwmac1000_dma_init(void __iomem *ioaddr, - struct stmmac_dma_cfg *dma_cfg, int atds) +void dwmac1000_dma_init(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, int atds) { u32 value = readl(ioaddr + DMA_BUS_MODE); int txpbl = dma_cfg->txpbl ?: dma_cfg->pbl; @@ -109,24 +111,27 @@ static void dwmac1000_dma_init(void __iomem *ioaddr, /* Mask interrupts by writing to CSR7 */ writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA); } +EXPORT_SYMBOL_GPL(dwmac1000_dma_init); -static void dwmac1000_dma_init_rx(struct stmmac_priv *priv, - void __iomem *ioaddr, - struct stmmac_dma_cfg *dma_cfg, - dma_addr_t dma_rx_phy, u32 chan) +void dwmac1000_dma_init_rx(struct stmmac_priv *priv, + void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + dma_addr_t dma_rx_phy, u32 chan) { /* RX descriptor base address list must be written into DMA CSR3 */ writel(lower_32_bits(dma_rx_phy), ioaddr + DMA_RCV_BASE_ADDR); } +EXPORT_SYMBOL_GPL(dwmac1000_dma_init_rx); -static void dwmac1000_dma_init_tx(struct stmmac_priv *priv, - void __iomem *ioaddr, - struct stmmac_dma_cfg *dma_cfg, - dma_addr_t dma_tx_phy, u32 chan) +void dwmac1000_dma_init_tx(struct stmmac_priv *priv, + void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + dma_addr_t dma_tx_phy, u32 chan) { /* TX descriptor base address list must be written into DMA CSR4 */ writel(lower_32_bits(dma_tx_phy), ioaddr + DMA_TX_BASE_ADDR); } +EXPORT_SYMBOL_GPL(dwmac1000_dma_init_tx); static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz) { @@ -149,9 +154,9 @@ static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz) return csr6; } -static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv, - void __iomem *ioaddr, int mode, - u32 channel, int fifosz, u8 qmode) +void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv, + void __iomem *ioaddr, int mode, + u32 channel, int fifosz, u8 qmode) { u32 csr6 = readl(ioaddr + DMA_CONTROL); @@ -177,10 +182,11 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv, writel(csr6, ioaddr + DMA_CONTROL); } +EXPORT_SYMBOL_GPL(dwmac1000_dma_operation_mode_rx); -static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv, - void __iomem *ioaddr, int mode, - u32 channel, int fifosz, u8 qmode) +void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv, + void __iomem *ioaddr, int mode, + u32 channel, int fifosz, u8 qmode) { u32 csr6 = readl(ioaddr + DMA_CONTROL); @@ -211,9 +217,10 @@ static void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv, writel(csr6, ioaddr + DMA_CONTROL); } +EXPORT_SYMBOL_GPL(dwmac1000_dma_operation_mode_tx); -static void dwmac1000_dump_dma_regs(struct stmmac_priv *priv, - void __iomem *ioaddr, u32 *reg_space) +void dwmac1000_dump_dma_regs(struct stmmac_priv *priv, + void __iomem *ioaddr, u32 *reg_space) { int i; @@ -222,9 +229,10 @@ static void dwmac1000_dump_dma_regs(struct stmmac_priv *priv, reg_space[DMA_BUS_MODE / 4 + i] = readl(ioaddr + DMA_BUS_MODE + i * 4); } +EXPORT_SYMBOL_GPL(dwmac1000_dump_dma_regs); -static int dwmac1000_get_hw_feature(void __iomem *ioaddr, - struct dma_features *dma_cap) +int dwmac1000_get_hw_feature(void __iomem *ioaddr, + struct dma_features *dma_cap) { u32 hw_cap = readl(ioaddr + DMA_HW_FEATURE); @@ -267,12 +275,14 @@ static int dwmac1000_get_hw_feature(void __iomem *ioaddr, return 0; } +EXPORT_SYMBOL_GPL(dwmac1000_get_hw_feature); -static void dwmac1000_rx_watchdog(struct stmmac_priv *priv, - void __iomem *ioaddr, u32 riwt, u32 queue) +void dwmac1000_rx_watchdog(struct stmmac_priv *priv, + void __iomem *ioaddr, u32 riwt, u32 queue) { writel(riwt, ioaddr + DMA_RX_WATCHDOG); } +EXPORT_SYMBOL_GPL(dwmac1000_rx_watchdog); const struct stmmac_dma_ops dwmac1000_dma_ops = { .reset = dwmac_dma_reset, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h new file mode 100644 index 0000000000000..34c10eb03a10b --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __DWMAC1000_DMA_H__ +#define __DWMAC1000_DMA_H__ +#include "dwmac1000.h" + +void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi); +void dwmac1000_dma_init(void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, int atds); +void dwmac1000_dma_init_rx(struct stmmac_priv *priv, + void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + dma_addr_t dma_rx_phy, u32 chan); +void dwmac1000_dma_init_tx(struct stmmac_priv *priv, + void __iomem *ioaddr, + struct stmmac_dma_cfg *dma_cfg, + dma_addr_t dma_tx_phy, u32 chan); +void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv, + void __iomem *ioaddr, int mode, + u32 channel, int fifosz, u8 qmode); +void dwmac1000_dma_operation_mode_tx(struct stmmac_priv *priv, + void __iomem *ioaddr, int mode, + u32 channel, int fifosz, u8 qmode); +void dwmac1000_dump_dma_regs(struct stmmac_priv *priv, + void __iomem *ioaddr, u32 *reg_space); + +int dwmac1000_get_hw_feature(void __iomem *ioaddr, + struct dma_features *dma_cap); + +void dwmac1000_rx_watchdog(struct stmmac_priv *priv, + void __iomem *ioaddr, u32 riwt, u32 number_chan); +#endif /* __DWMAC1000_DMA_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 85e18f9a22f92..12e7f2c081f93 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -32,6 +32,7 @@ void dwmac_enable_dma_transmission(void __iomem *ioaddr) { writel(1, ioaddr + DMA_XMT_POLL_DEMAND); } +EXPORT_SYMBOL_GPL(dwmac_enable_dma_transmission); void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan, bool rx, bool tx) @@ -45,6 +46,7 @@ void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, writel(value, ioaddr + DMA_INTR_ENA); } +EXPORT_SYMBOL_GPL(dwmac_enable_dma_irq); void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan, bool rx, bool tx) @@ -58,6 +60,7 @@ void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, writel(value, ioaddr + DMA_INTR_ENA); } +EXPORT_SYMBOL_GPL(dwmac_disable_dma_irq); void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) @@ -66,6 +69,7 @@ void dwmac_dma_start_tx(struct stmmac_priv *priv, void __iomem *ioaddr, value |= DMA_CONTROL_ST; writel(value, ioaddr + DMA_CONTROL); } +EXPORT_SYMBOL_GPL(dwmac_dma_start_tx); void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) { @@ -73,6 +77,7 @@ void dwmac_dma_stop_tx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) value &= ~DMA_CONTROL_ST; writel(value, ioaddr + DMA_CONTROL); } +EXPORT_SYMBOL_GPL(dwmac_dma_stop_tx); void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) @@ -81,6 +86,7 @@ void dwmac_dma_start_rx(struct stmmac_priv *priv, void __iomem *ioaddr, value |= DMA_CONTROL_SR; writel(value, ioaddr + DMA_CONTROL); } +EXPORT_SYMBOL_GPL(dwmac_dma_start_rx); void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) { @@ -88,6 +94,7 @@ void dwmac_dma_stop_rx(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan) value &= ~DMA_CONTROL_SR; writel(value, ioaddr + DMA_CONTROL); } +EXPORT_SYMBOL_GPL(dwmac_dma_stop_rx); #ifdef DWMAC_DMA_DEBUG static void show_tx_process_state(unsigned int status) @@ -239,6 +246,7 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, return ret; } +EXPORT_SYMBOL_GPL(dwmac_dma_interrupt); void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr) { diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 049c3adeb8504..643ab458e25ef 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -560,6 +560,7 @@ int nvmem_get_mac_address(struct device *dev, void *addrbuf) return 0; } +EXPORT_SYMBOL(nvmem_get_mac_address); static int fwnode_get_mac_addr(struct fwnode_handle *fwnode, const char *name, char *addr) -- 2.42.2