mirror of
https://abf.rosa.ru/djam/kernel-5.15.git
synced 2025-02-23 18:42:55 +00:00
279 lines
8 KiB
Diff
279 lines
8 KiB
Diff
![]() |
From 8d0e122d3d4979e32c6ad0d340d8c9b31a8b4d95 Mon Sep 17 00:00:00 2001
|
||
|
From: Alexey Sheplyakov <asheplyakov@altlinux.org>
|
||
|
Date: Fri, 20 Mar 2020 14:00:56 +0400
|
||
|
Subject: [PATCH 606/625] stmmac: Baikal-M dwmac driver
|
||
|
|
||
|
(cherry picked from commit 5fd65e2b57a4873946822e99fb74b07caa73c341)
|
||
|
---
|
||
|
drivers/net/ethernet/stmicro/stmmac/Kconfig | 10 +
|
||
|
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
|
||
|
.../ethernet/stmicro/stmmac/dwmac-baikal.c | 223 ++++++++++++++++++
|
||
|
3 files changed, 234 insertions(+)
|
||
|
create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
|
||
|
|
||
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
|
||
|
index 53f14c5a9e02..26a3f62a36cc 100644
|
||
|
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
|
||
|
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
|
||
|
@@ -66,6 +66,16 @@ config DWMAC_ANARION
|
||
|
|
||
|
This selects the Anarion SoC glue layer support for the stmmac driver.
|
||
|
|
||
|
+config DWMAC_BAIKAL
|
||
|
+ tristate "Baikal Electronics DWMAC support"
|
||
|
+ default y if MIPS_BAIKAL || ARCH_BAIKAL
|
||
|
+ depends on OF
|
||
|
+ help
|
||
|
+ Support for Baikal Electronics DWMAC Ethernet.
|
||
|
+
|
||
|
+ This selects the Baikal-T/M SoC glue layer support for the stmmac
|
||
|
+ device driver.
|
||
|
+
|
||
|
config DWMAC_IPQ806X
|
||
|
tristate "QCA IPQ806x DWMAC support"
|
||
|
default ARCH_QCOM
|
||
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
|
||
|
index 24e6145d4eae..64970f60f536 100644
|
||
|
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
|
||
|
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
|
||
|
@@ -13,6 +13,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_IPQ806X) += dwmac-ipq806x.o
|
||
|
obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
|
||
|
obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.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 000000000000..646051cd500d
|
||
|
--- /dev/null
|
||
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-baikal.c
|
||
|
@@ -0,0 +1,223 @@
|
||
|
+/*
|
||
|
+ * Baikal Electronics SoCs DWMAC glue layer
|
||
|
+ *
|
||
|
+ * Copyright (C) 2015,2016 Baikal Electronics JSC
|
||
|
+ * Author:
|
||
|
+ * Dmitry Dunaev <dmitry.dunaev@baikalelectronics.ru>
|
||
|
+ * All bugs by Alexey Sheplyakov <asheplyakov@altlinux.org>
|
||
|
+ *
|
||
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
+ * it under the terms of the GNU General Public License version 2 as
|
||
|
+ * published by the Free Software Foundation.
|
||
|
+ *
|
||
|
+ * You should have received a copy of the GNU General Public License
|
||
|
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
+ */
|
||
|
+
|
||
|
+#include <linux/iopoll.h>
|
||
|
+#include <linux/module.h>
|
||
|
+#include <linux/of.h>
|
||
|
+#include <linux/platform_device.h>
|
||
|
+#include <linux/clk.h>
|
||
|
+
|
||
|
+#include "stmmac.h"
|
||
|
+#include "stmmac_platform.h"
|
||
|
+#include "common.h"
|
||
|
+#include "dwmac_dma.h"
|
||
|
+#include "dwmac1000_dma.h"
|
||
|
+
|
||
|
+#define MAC_GPIO 0x000000e0 /* GPIO register */
|
||
|
+#define MAC_GPIO_GPO0 (1 << 8) /* 0-output port */
|
||
|
+
|
||
|
+struct baikal_dwmac {
|
||
|
+ struct device *dev;
|
||
|
+ struct clk *tx2_clk;
|
||
|
+};
|
||
|
+
|
||
|
+static int baikal_dwmac_dma_reset(void __iomem *ioaddr)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+ u32 value = readl(ioaddr + DMA_BUS_MODE);
|
||
|
+
|
||
|
+ /* DMA SW reset */
|
||
|
+ value |= DMA_BUS_MODE_SFT_RESET;
|
||
|
+ writel(value, ioaddr + DMA_BUS_MODE);
|
||
|
+
|
||
|
+ udelay(10);
|
||
|
+ /* Clear PHY reset */
|
||
|
+ value = readl(ioaddr + MAC_GPIO);
|
||
|
+ value |= MAC_GPIO_GPO0;
|
||
|
+ writel(value, ioaddr + MAC_GPIO);
|
||
|
+ pr_info("PHY re-inited for Baikal DWMAC\n");
|
||
|
+
|
||
|
+ 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_dwmac_dma_ops = {
|
||
|
+ .reset = baikal_dwmac_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_dwmac_setup(void *ppriv)
|
||
|
+{
|
||
|
+ struct mac_device_info *mac, *old_mac;
|
||
|
+ struct stmmac_priv *priv = ppriv;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
|
||
|
+ if (!mac)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ mac->dma = &baikal_dwmac_dma_ops;
|
||
|
+ old_mac = priv->hw;
|
||
|
+ priv->hw = mac;
|
||
|
+ ret = dwmac1000_setup(priv);
|
||
|
+ priv->hw = old_mac;
|
||
|
+ if (ret) {
|
||
|
+ dev_err(priv->device, "dwmac1000_setup: error %d", ret);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ return mac;
|
||
|
+}
|
||
|
+
|
||
|
+static void baikal_dwmac_fix_mac_speed(void *priv, unsigned int speed)
|
||
|
+{
|
||
|
+ struct baikal_dwmac *dwmac = priv;
|
||
|
+ unsigned long tx2_clk_freq = 0;
|
||
|
+ dev_info(dwmac->dev, "fix_mac_speed new speed %u\n", speed);
|
||
|
+ switch (speed) {
|
||
|
+ case SPEED_1000:
|
||
|
+ tx2_clk_freq = 250000000;
|
||
|
+ break;
|
||
|
+ case SPEED_100:
|
||
|
+ tx2_clk_freq = 50000000;
|
||
|
+ break;
|
||
|
+ case SPEED_10:
|
||
|
+ tx2_clk_freq = 5000000;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (dwmac->tx2_clk && tx2_clk_freq != 0) {
|
||
|
+ dev_info(dwmac->dev, "setting TX2 clock frequency to %lu\n", tx2_clk_freq);
|
||
|
+ clk_set_rate(dwmac->tx2_clk, tx2_clk_freq);
|
||
|
+
|
||
|
+ }
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
+static int dwmac_baikal_probe(struct platform_device *pdev)
|
||
|
+{
|
||
|
+ struct plat_stmmacenet_data *plat_dat;
|
||
|
+ struct stmmac_resources stmmac_res;
|
||
|
+ struct baikal_dwmac *dwmac;
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ 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, &stmmac_res.mac);
|
||
|
+ if (IS_ERR(plat_dat)) {
|
||
|
+ dev_err(&pdev->dev, "dt configuration failed\n");
|
||
|
+ return PTR_ERR(plat_dat);
|
||
|
+ }
|
||
|
+ } 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;
|
||
|
+ }
|
||
|
+
|
||
|
+ dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
|
||
|
+ if (!dwmac) {
|
||
|
+ ret = -ENOMEM;
|
||
|
+ goto err_remove_config_dt;
|
||
|
+ }
|
||
|
+
|
||
|
+ dwmac->dev = &pdev->dev;
|
||
|
+ dwmac->tx2_clk = devm_clk_get(dwmac->dev, "tx2_clk");
|
||
|
+ if (IS_ERR(dwmac->tx2_clk)) {
|
||
|
+ dev_warn(&pdev->dev, "coldn't get TX2 clock\n");
|
||
|
+ dwmac->tx2_clk = NULL;
|
||
|
+ }
|
||
|
+ plat_dat->fix_mac_speed = baikal_dwmac_fix_mac_speed;
|
||
|
+ plat_dat->bsp_priv = dwmac;
|
||
|
+
|
||
|
+ plat_dat->has_gmac = 1;
|
||
|
+ plat_dat->enh_desc = 1;
|
||
|
+ plat_dat->tx_coe = 1;
|
||
|
+ plat_dat->rx_coe = 1;
|
||
|
+ // TODO: set CSR correct clock in dts!
|
||
|
+ plat_dat->clk_csr = 3;
|
||
|
+ plat_dat->setup = baikal_dwmac_setup;
|
||
|
+
|
||
|
+ dev_info(&pdev->dev, "Baikal Electronics DWMAC glue driver\n");
|
||
|
+
|
||
|
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||
|
+ if (ret)
|
||
|
+ goto err_remove_config_dt;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+
|
||
|
+err_remove_config_dt:
|
||
|
+ stmmac_remove_config_dt(pdev, plat_dat);
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static const struct of_device_id dwmac_baikal_match[] = {
|
||
|
+ { .compatible = "be,dwmac-3.710"},
|
||
|
+ { .compatible = "be,dwmac"},
|
||
|
+ { }
|
||
|
+};
|
||
|
+MODULE_DEVICE_TABLE(of, dwmac_baikal_match);
|
||
|
+
|
||
|
+static struct platform_driver dwmac_baikal_driver = {
|
||
|
+ .probe = dwmac_baikal_probe,
|
||
|
+ .remove = stmmac_pltfr_remove,
|
||
|
+ .driver = {
|
||
|
+ .name = "baikal-dwmac",
|
||
|
+ .pm = &stmmac_pltfr_pm_ops,
|
||
|
+ .of_match_table = of_match_ptr(dwmac_baikal_match),
|
||
|
+ },
|
||
|
+};
|
||
|
+module_platform_driver(dwmac_baikal_driver);
|
||
|
+
|
||
|
+MODULE_DESCRIPTION("Baikal dwmac glue driver");
|
||
|
+MODULE_LICENSE("GPL v2");
|
||
|
--
|
||
|
2.31.1
|
||
|
|