[PATCH] net: stmmac: Move Loongson1 MAC arch-code to the driver dir
From: Serge Semin
Date: Sun Sep 26 2021 - 16:41:51 EST
Loongson1 SoC is equipped with two GMAC interfaces based on the DW GMAC
v3.x. Both of them are exposed on Loongson 1B boards, and just one of them
- on Loongson 1C boards. The glue driver has been created purely based on
the arch-code implemented earlier with the platform-specific settings.
That's why the sloppy mux-switching has been left as is until someone
dares to create a driver for the embedded mux.
Note after this commit is merged in there won't be any platform_data-based
code left using the STMMAC-platform interface. Thus the STMMAC
platform_data declarations can be freely moved away from the generic
kernel headers set into the driver directory.
Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
---
Note I don't have a Loongson32 hardware at hand to test it out. I've
built-test the change though. So should you have the hardware any tests
and bug-reports would be very welcome.
---
MAINTAINERS | 1 +
arch/mips/loongson32/common/platform.c | 111 +----------
drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 ++
drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
.../ethernet/stmicro/stmmac/dwmac-loongson1.c | 173 ++++++++++++++++++
5 files changed, 193 insertions(+), 104 deletions(-)
create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c
diff --git a/MAINTAINERS b/MAINTAINERS
index f0ee1d6d8918..a90d5b3de82e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14097,6 +14097,7 @@ L: linux-mips@xxxxxxxxxxxxxxx
S: Maintained
F: arch/mips/include/asm/mach-loongson32/
F: arch/mips/loongson32/
+F: drivers/*/*/*/*/*loongson1*
F: drivers/*/*loongson1*
MIPS/LOONGSON2EF ARCHITECTURE
diff --git a/arch/mips/loongson32/common/platform.c b/arch/mips/loongson32/common/platform.c
index 64d7979394e6..85603f531148 100644
--- a/arch/mips/loongson32/common/platform.c
+++ b/arch/mips/loongson32/common/platform.c
@@ -10,7 +10,6 @@
#include <linux/sizes.h>
#include <linux/phy.h>
#include <linux/serial_8250.h>
-#include <linux/stmmac.h>
#include <linux/usb/ehci_pdriver.h>
#include <platform.h>
@@ -61,88 +60,7 @@ void __init ls1x_serial_set_uartclk(struct platform_device *pdev)
p->uartclk = clk_get_rate(clk);
}
-/* Synopsys Ethernet GMAC */
-static struct stmmac_mdio_bus_data ls1x_mdio_bus_data = {
- .phy_mask = 0,
-};
-
-static struct stmmac_dma_cfg ls1x_eth_dma_cfg = {
- .pbl = 1,
-};
-
-int ls1x_eth_mux_init(struct platform_device *pdev, void *priv)
-{
- struct plat_stmmacenet_data *plat_dat = NULL;
- u32 val;
-
- val = __raw_readl(LS1X_MUX_CTRL1);
-
-#if defined(CONFIG_LOONGSON1_LS1B)
- plat_dat = dev_get_platdata(&pdev->dev);
- if (plat_dat->bus_id) {
- __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
- GMAC1_USE_UART0, LS1X_MUX_CTRL0);
- switch (plat_dat->phy_interface) {
- case PHY_INTERFACE_MODE_RGMII:
- val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
- break;
- case PHY_INTERFACE_MODE_MII:
- val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
- break;
- default:
- pr_err("unsupported mii mode %d\n",
- plat_dat->phy_interface);
- return -ENOTSUPP;
- }
- val &= ~GMAC1_SHUT;
- } else {
- switch (plat_dat->phy_interface) {
- case PHY_INTERFACE_MODE_RGMII:
- val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
- break;
- case PHY_INTERFACE_MODE_MII:
- val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
- break;
- default:
- pr_err("unsupported mii mode %d\n",
- plat_dat->phy_interface);
- return -ENOTSUPP;
- }
- val &= ~GMAC0_SHUT;
- }
- __raw_writel(val, LS1X_MUX_CTRL1);
-#elif defined(CONFIG_LOONGSON1_LS1C)
- plat_dat = dev_get_platdata(&pdev->dev);
-
- val &= ~PHY_INTF_SELI;
- if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII)
- val |= 0x4 << PHY_INTF_SELI_SHIFT;
- __raw_writel(val, LS1X_MUX_CTRL1);
-
- val = __raw_readl(LS1X_MUX_CTRL0);
- __raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0);
-#endif
-
- return 0;
-}
-
-static struct plat_stmmacenet_data ls1x_eth0_pdata = {
- .bus_id = 0,
- .phy_addr = -1,
-#if defined(CONFIG_LOONGSON1_LS1B)
- .phy_interface = PHY_INTERFACE_MODE_MII,
-#elif defined(CONFIG_LOONGSON1_LS1C)
- .phy_interface = PHY_INTERFACE_MODE_RMII,
-#endif
- .mdio_bus_data = &ls1x_mdio_bus_data,
- .dma_cfg = &ls1x_eth_dma_cfg,
- .has_gmac = 1,
- .tx_coe = 1,
- .rx_queues_to_use = 1,
- .tx_queues_to_use = 1,
- .init = ls1x_eth_mux_init,
-};
-
+/* Ethernet (Synopsys DW GMAC) */
static struct resource ls1x_eth0_resources[] = {
[0] = {
.start = LS1X_GMAC0_BASE,
@@ -157,29 +75,17 @@ static struct resource ls1x_eth0_resources[] = {
};
struct platform_device ls1x_eth0_pdev = {
- .name = "stmmaceth",
+#if defined(CONFIG_LOONGSON1_LS1B)
+ .name = "ls1b-eth",
+#elif defined(CONFIG_LOONGSON1_LS1C)
+ .name = "ls1c-eth",
+#endif
.id = 0,
.num_resources = ARRAY_SIZE(ls1x_eth0_resources),
.resource = ls1x_eth0_resources,
- .dev = {
- .platform_data = &ls1x_eth0_pdata,
- },
};
#ifdef CONFIG_LOONGSON1_LS1B
-static struct plat_stmmacenet_data ls1x_eth1_pdata = {
- .bus_id = 1,
- .phy_addr = -1,
- .phy_interface = PHY_INTERFACE_MODE_MII,
- .mdio_bus_data = &ls1x_mdio_bus_data,
- .dma_cfg = &ls1x_eth_dma_cfg,
- .has_gmac = 1,
- .tx_coe = 1,
- .rx_queues_to_use = 1,
- .tx_queues_to_use = 1,
- .init = ls1x_eth_mux_init,
-};
-
static struct resource ls1x_eth1_resources[] = {
[0] = {
.start = LS1X_GMAC1_BASE,
@@ -194,13 +100,10 @@ static struct resource ls1x_eth1_resources[] = {
};
struct platform_device ls1x_eth1_pdev = {
- .name = "stmmaceth",
+ .name = "ls1b-eth",
.id = 1,
.num_resources = ARRAY_SIZE(ls1x_eth1_resources),
.resource = ls1x_eth1_resources,
- .dev = {
- .platform_data = &ls1x_eth1_pdata,
- },
};
#endif /* CONFIG_LOONGSON1_LS1B */
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
index 5f5a997f21f3..a89ecbd67f21 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
@@ -263,6 +263,17 @@ config DWMAC_VISCONTI
help
Support for ethernet controller on Visconti SoCs.
+config DWMAC_LOONGSON1
+ tristate "Loongson1 GMAC support"
+ default LOONGSON1_LS1B || LOONGSON1_LS1C
+ depends on MACH_LOONGSON32
+ help
+ Support for ethernet controller on Loongson1 SoC.
+
+ This selects Loongson1 SoC glue layer support for the stmmac
+ device driver. This driver is used for Loongson1-based boards
+ like Loongson LS1B/LS1C.
+
endif
config DWMAC_INTEL
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 8738fdbb4b2d..a6fb0f773575 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
obj-$(CONFIG_DWMAC_IMX8) += dwmac-imx.o
obj-$(CONFIG_DWMAC_TEGRA) += dwmac-tegra.o
obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o
+obj-$(CONFIG_DWMAC_LOONGSON1) += dwmac-loongson1.o
stmmac-platform-objs:= stmmac_platform.o
dwmac-altr-socfpga-objs := altr_tse_pcs.o dwmac-socfpga.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c
new file mode 100644
index 000000000000..4cf6e763ac41
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2011-2023 Zhang, Keguang <keguang.zhang@xxxxxxxxx>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/io.h>
+
+#include <asm/mach-loongson32/loongson1.h>
+
+#include "stmmac.h"
+#include "stmmac_platform.h"
+
+struct ls1x_eth_info {
+ phy_interface_t interface;
+ int (*init)(struct platform_device *pdev, void *priv);
+};
+
+/* Note the mux-switching is supposed to be implemented via a dedicated
+ * driver. Until it's done there is no other choice but live with such
+ * a sloppy implementation.
+ */
+static int ls1b_eth_mux_init(struct platform_device *pdev, void *priv)
+{
+ struct plat_stmmacenet_data *plat = priv;
+ u32 val;
+
+ val = __raw_readl(LS1X_MUX_CTRL1);
+
+ if (plat->bus_id) {
+ __raw_writel(__raw_readl(LS1X_MUX_CTRL0) | GMAC1_USE_UART1 |
+ GMAC1_USE_UART0, LS1X_MUX_CTRL0);
+ switch (plat->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val &= ~(GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ val |= (GMAC1_USE_TXCLK | GMAC1_USE_PWM23);
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported PHY-mode %u\n",
+ plat->phy_interface);
+ return -ENOTSUPP;
+ }
+ val &= ~GMAC1_SHUT;
+ } else {
+ switch (plat->phy_interface) {
+ case PHY_INTERFACE_MODE_RGMII:
+ val &= ~(GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ val |= (GMAC0_USE_TXCLK | GMAC0_USE_PWM01);
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported PHY-mode %u\n",
+ plat->phy_interface);
+ return -ENOTSUPP;
+ }
+ val &= ~GMAC0_SHUT;
+ }
+
+ __raw_writel(val, LS1X_MUX_CTRL1);
+
+ return 0;
+}
+
+static int ls1c_eth_mux_init(struct platform_device *pdev, void *priv)
+{
+ struct plat_stmmacenet_data *plat = priv;
+ u32 val;
+
+ val = __raw_readl(LS1X_MUX_CTRL1) & ~PHY_INTF_SELI;
+ if (plat->phy_interface == PHY_INTERFACE_MODE_RMII) {
+ val |= 0x4 << PHY_INTF_SELI_SHIFT;
+ } else {
+ dev_err(&pdev->dev, "Unsupported PHY-mode %u\n",
+ plat->phy_interface);
+ return -ENOTSUPP;
+ }
+ __raw_writel(val, LS1X_MUX_CTRL1);
+
+ val = __raw_readl(LS1X_MUX_CTRL0);
+ __raw_writel(val & (~GMAC_SHUT), LS1X_MUX_CTRL0);
+
+ return 0;
+}
+
+static int ls1x_eth_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ const struct ls1x_eth_info *info = (struct ls1x_eth_info *)id->driver_data;
+ 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_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
+ if (!plat)
+ return -ENOMEM;
+
+ plat->mdio_bus_data = devm_kzalloc(&pdev->dev,
+ sizeof(*plat->mdio_bus_data),
+ GFP_KERNEL);
+ if (!plat->mdio_bus_data)
+ return -ENOMEM;
+
+ plat->dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*plat->dma_cfg),
+ GFP_KERNEL);
+ if (!plat->dma_cfg)
+ return -ENOMEM;
+
+ plat->bus_id = pdev->id;
+ plat->phy_addr = -1;
+ plat->phy_interface = info->phy_interface;
+ plat->mdio_bus_data->phy_mask = 0;
+ plat->dma_cfg->pbl = 1;
+ plat->has_gmac = 1;
+ plat->tx_coe = 1;
+ plat->multicast_filter_bins = 64;
+ plat->unicast_filter_entries = 1;
+ plat->rx_queues_to_use = 1;
+ plat->tx_queues_to_use = 1;
+ plat->bsp_priv = plat;
+ plat->init = info->init;
+
+ ret = plat->init(pdev, plat->bsp_priv);
+ if (ret)
+ return ret;
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat, &stmmac_res);
+ if (ret)
+ goto err_exit;
+
+ return 0;
+}
+
+static const struct ls1x_eth_info ls1b_eth_info = {
+ .phy_interface = PHY_INTERFACE_MODE_MII,
+ .init = ls1b_eth_mux_init,
+};
+
+static const struct ls1x_eth_info ls1c_eth_info = {
+ .phy_interface = PHY_INTERFACE_MODE_RMII,
+ .init = ls1c_eth_mux_init,
+};
+
+static const struct platform_device_id ls1x_eth_id_table[] = {
+ { "ls1b-eth", (kernel_ulong_t)&ls1b_eth_info },
+ { "ls1c-eth", (kernel_ulong_t)&ls1c_eth_info },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, ls1x_eth_id_table);
+
+static struct platform_driver ls1x_eth_driver = {
+ .probe = ls1x_eth_probe,
+ .remove = stmmac_pltfr_remove,
+ .id_table = ls1x_eth_id_table,
+ .driver = {
+ .name = "ls1x-eth",
+ },
+};
+module_platform_driver(ls1x_eth_driver);
+
+MODULE_AUTHOR("Keguang Zhang <keguang.zhang@xxxxxxxxx>");
+MODULE_DESCRIPTION("Loongson1 GMAC driver");
+MODULE_LICENSE("GPL");
--
2.41.0
--tecqq4v2edoarqvd--