From: George Moussalem Date: Sun, 17 May 2026 18:19:35 +0000 (+0200) Subject: qualcommax: ipq50xx: add Qualcomm IPQ5018 DWMAC driver X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b910cbfc0c5d538f695d2234d6425587434c14e6;p=thirdparty%2Fopenwrt.git qualcommax: ipq50xx: add Qualcomm IPQ5018 DWMAC driver Add IPQ5018 DWMAC driver. IP version of this Synopsys DWMAC is 3.7. This Qualcomm IPQ5018 specific MAC implementation supports link speeds of 10HD/FD, 100HD/FD, 1,000HD/FD, and 2500FD and SGMII and 2500BASEX interface modes. The driver supports the MAC be attached directly to a PHY or via an optional PCS to a switch or PHY. Signed-off-by: George Moussalem Link: https://github.com/openwrt/openwrt/pull/22381 Signed-off-by: Robert Marko --- diff --git a/target/linux/qualcommax/files/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq5018.c b/target/linux/qualcommax/files/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq5018.c new file mode 100644 index 00000000000..78f22e1c8b8 --- /dev/null +++ b/target/linux/qualcommax/files/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq5018.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Qualcomm IPQ5018 DWMAC glue layer + * + * Copyright (C) 2026 The OpenWrt Project + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "stmmac_platform.h" + +#define MAX_FRAME_SIZE 16383 /* 14 bits */ +/* MAX_MTU = (MAX_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN - (2 * VLAN_HLEN)) */ +#define MAX_MTU 16357 + +static struct clk_bulk_data ipq5018_gmac_clks[] = { + { .id = "stmmaceth" }, + { .id = "pclk" }, + { .id = "ptp_ref" }, + { .id = "ahb" }, + { .id = "axi" }, + { .id = "rx" }, + { .id = "tx" }, +}; + +struct ipq5018_gmac { + struct device *dev; + struct clk *rx_clk; + struct clk *tx_clk; +}; + +static void ipq5018_gmac_fix_speed(void *priv, unsigned int speed, unsigned int mode) +{ + struct ipq5018_gmac *gmac = priv; + unsigned long rate; + + switch(speed) { + case SPEED_10: + rate = 2500000; + break; + case SPEED_100: + rate = 25000000; + break; + case SPEED_1000: + rate = 125000000; + break; + case SPEED_2500: + rate = 312500000; + break; + default: + dev_err(gmac->dev, "Unsupported speed: %d\n", speed); + rate = 125000000; + break; + } + + clk_set_rate(gmac->rx_clk, rate); + clk_set_rate(gmac->tx_clk, rate); +} + +static int ipq5018_gmac_pcs_init(struct stmmac_priv *priv) +{ + struct phylink_pcs *pcs; + int ret; + + pcs = fwnode_pcs_get(dev_fwnode(priv->device), 0); + if (!pcs) + return 0; + else if (IS_ERR(pcs)) { + ret = PTR_ERR(pcs); + if (ret == -ENOENT) + return 0; + dev_err(priv->device, "failed to parse PCS from fwnode\n"); + return ret; + } + + priv->hw->phylink_pcs = pcs; + + return 0; +} + +static struct phylink_pcs *ipq5018_gmac_select_pcs(struct stmmac_priv *priv, + phy_interface_t interface) +{ + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + if (priv->hw->phylink_pcs) + return priv->hw->phylink_pcs; + default: + break; + } + + return NULL; +} + +static void ipq5018_gmac_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, + unsigned long *interfaces) +{ + struct mac_device_info *mac = priv->hw; + + /* + * IPQ5018 has two GMACs: + * - GMAC0 supports SGMII and is wired to the SoC's internal GE PHY + * - GMAC1 supports SGMII and 2500BaseX, configurable by the UNIPHY PCS + */ + __set_bit(PHY_INTERFACE_MODE_SGMII, interfaces); + if (priv->hw->phylink_pcs) { + __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces); + + /* + * Synopsys DWMAC IP version 3.7 is limited to 1 Gpbs. + * This vendor specific implementation supports 2.5 Gbps, so override + * the default mac link capabilities. + */ + mac->link.caps |= MAC_2500FD; + } +} + +static int ipq5018_gmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct device *dev = &pdev->dev; + struct ipq5018_gmac *gmac; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return dev_err_probe(dev, ret, + "failed to get stmmac platform resources\n"); + + plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR_OR_NULL(plat_dat)) + return dev_err_probe(dev, PTR_ERR(plat_dat), + "failed to parse stmmac dt parameters\n"); + + gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); + if (!gmac) + return dev_err_probe(dev, -ENOMEM, + "failed to allocate priv\n"); + + gmac->dev = dev; + + gmac->rx_clk = devm_clk_get(dev, "rx"); + if (IS_ERR(gmac->rx_clk)) + return dev_err_probe(dev, PTR_ERR(gmac->rx_clk), + "failed to get RX clock\n"); + + gmac->tx_clk = devm_clk_get(dev, "tx"); + if (IS_ERR(gmac->tx_clk)) + return dev_err_probe(dev, PTR_ERR(gmac->tx_clk), + "failed to get TX clock\n"); + + ret = devm_clk_bulk_get(dev, ARRAY_SIZE(ipq5018_gmac_clks), + ipq5018_gmac_clks); + if (ret) + return dev_err_probe(dev, ret, "failed to get clocks\n"); + + ret = clk_bulk_prepare_enable(ARRAY_SIZE(ipq5018_gmac_clks), + ipq5018_gmac_clks); + if (ret) + return dev_err_probe(dev, ret, "failed to enable clocks\n"); + + plat_dat->bsp_priv = gmac; + plat_dat->max_speed = 2500; + plat_dat->maxmtu = MAX_MTU; + plat_dat->rx_fifo_size = MAX_FRAME_SIZE; + plat_dat->tx_fifo_size = MAX_FRAME_SIZE; + plat_dat->get_interfaces = ipq5018_gmac_get_interfaces; + plat_dat->fix_mac_speed = ipq5018_gmac_fix_speed; + plat_dat->pcs_init = ipq5018_gmac_pcs_init; + plat_dat->select_pcs = ipq5018_gmac_select_pcs; + + return stmmac_dvr_probe(dev, plat_dat, &stmmac_res); +} + +static const struct of_device_id ipq5018_gmac_dwmac_match[] = { + { .compatible = "qcom,ipq5018-gmac" }, + { } +}; +MODULE_DEVICE_TABLE(of, ipq5018_gmac_dwmac_match); + +static struct platform_driver ipq5018_gmac_dwmac_driver = { + .probe = ipq5018_gmac_probe, + .driver = { + .name = "ipq5018-gmac-dwmac", + .of_match_table = ipq5018_gmac_dwmac_match, + }, +}; +module_platform_driver(ipq5018_gmac_dwmac_driver); + +MODULE_DESCRIPTION("Qualcomm IPQ5018 DWMAC glue layer"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/target/linux/qualcommax/files/include/dt-bindings/net/qcom,ipq5018-gmac.yaml b/target/linux/qualcommax/files/include/dt-bindings/net/qcom,ipq5018-gmac.yaml new file mode 100644 index 00000000000..15906428775 --- /dev/null +++ b/target/linux/qualcommax/files/include/dt-bindings/net/qcom,ipq5018-gmac.yaml @@ -0,0 +1,131 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/net/qcom,ipq5018-gmac.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Qualcomm IPQ5018 DWMAC glue layer (GMAC) + +maintainers: + - George Moussalem + +description: | + This file documents platform glue layer for Qualcomm IPQ5018 DWMAC (GMAC) + The MAC supports speeds of 10/100/1000/2500 Mbps and supports SGMII and + 2500base-x interface modes. The IPQ5018 SoC has two GMACs: + The first MAC (GMAC0) is connected to an the SoC's internal IPQ5018 ethernet + GE PHY while the second MAC is connected to the SoC's UNIPHY PCS which is turn + can be wired to an external switch or PHY. + This MAC is of Synopsys DesignWare IP version 3.70a. + +# We need a select here so we don't match all nodes with 'snps,dwmac' +select: + properties: + compatible: + contains: + enum: + - qcom,ipq5018-gmac + required: + - compatible + +properties: + compatible: + items: + - enum: + - qcom,ipq5018-gmac + - const: snps,dwmac + + reg: true + + reg-names: + items: + - const: stmmaceth + + clocks: + minItems: 7 + + clock-names: + contains: + enum: + - stmmaceth + - pclk + - ptp_ref + - ahb + - axi + - rx + - tx + + resets: true + + reset-names: + items: + - const: stmmaceth + + interrupts: + minItems: 1 + + interrupt-names: + items: + - const: macirq + + pcs-handle: + $ref: ethernet-controller.yaml#/properties/pcs-handle + description: + A reference to an optional PCS PHY device (GMAC1 <-> UNIPHY PCS) + +required: + - compatible + - clocks + - clock-names + - resets + - reset-names + - interrupts + - interrupt-names + +allOf: + - $ref: snps,dwmac.yaml# + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + + gmac1: ethernet@39d00000 { + compatible = "qcom,ipq5018-gmac", "snps,dwmac"; + reg = <0x39d00000 0x10000>; + reg-names = "stmmaceth"; + clocks = <&gcc GCC_GMAC1_SYS_CLK>, + <&gcc GCC_GMAC1_CFG_CLK>, + <&gcc GCC_GMAC1_PTP_CLK>, + <&gcc GCC_SNOC_GMAC1_AHB_CLK>, + <&gcc GCC_SNOC_GMAC1_AXI_CLK>, + <&gcc GCC_GMAC1_RX_CLK>, + <&gcc GCC_GMAC1_TX_CLK>; + clock-names = "stmmaceth", + "pclk", + "ptp_ref", + "ahb", + "axi", + "rx", + "tx"; + assigned-clocks = <&gcc GCC_GMAC1_SYS_CLK>, + <&gcc GCC_GMAC1_CFG_CLK>, + <&gcc GCC_GMAC1_PTP_CLK>, + <&gcc GCC_SNOC_GMAC1_AHB_CLK>, + <&gcc GCC_SNOC_GMAC1_AXI_CLK>; + assigned-clock-rates = <240000000>, + <240000000>, + <240000000>, + <240000000>, + <240000000>; + resets = <&gcc GCC_GMAC1_BCR>; + reset-names = "stmmaceth"; + interrupts = ; + interrupt-names = "macirq"; + + phy-mode = "sgmii"; + pcs-handle = <&uniphy0>; + }; diff --git a/target/linux/qualcommax/patches-6.12/0843-net-stmmac-add-get_interfaces-platform-method.patch b/target/linux/qualcommax/patches-6.12/0843-net-stmmac-add-get_interfaces-platform-method.patch new file mode 100644 index 00000000000..3e415d24fbd --- /dev/null +++ b/target/linux/qualcommax/patches-6.12/0843-net-stmmac-add-get_interfaces-platform-method.patch @@ -0,0 +1,56 @@ +From ca732e990fc8222a2d6782ae750304719e212fe8 Mon Sep 17 00:00:00 2001 +From: "Russell King (Oracle)" +Date: Thu, 1 May 2025 12:45:11 +0100 +Subject: [PATCH] net: stmmac: add get_interfaces() platform method + +Add a get_interfaces() platform method to allow platforms to indicate +to phylink which interface modes they support - which then allows +phylink to validate on initialisation that the configured PHY interface +mode is actually supported. + +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1uASLn-0021Qd-Mi@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +--- + .../net/ethernet/stmicro/stmmac/stmmac_main.c | 16 +++++++++++++--- + include/linux/stmmac.h | 2 ++ + 2 files changed, 15 insertions(+), 3 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -1250,10 +1250,21 @@ static int stmmac_phy_setup(struct stmma + priv->phylink_config.default_an_inband = + mdio_bus_data->default_an_inband; + +- /* Set the platform/firmware specified interface mode. Note, phylink +- * deals with the PHY interface mode, not the MAC interface mode. ++ /* Get the PHY interface modes (at the PHY end of the link) that ++ * are supported by the platform. + */ +- __set_bit(mode, priv->phylink_config.supported_interfaces); ++ if (priv->plat->get_interfaces) ++ priv->plat->get_interfaces(priv, priv->plat->bsp_priv, ++ priv->phylink_config.supported_interfaces); ++ ++ /* Set the platform/firmware specified interface mode if the ++ * supported interfaces have not already been provided using ++ * phy_interface as a last resort. ++ */ ++ if (phy_interface_empty(priv->phylink_config.supported_interfaces)) ++ __set_bit(priv->plat->phy_interface, ++ priv->phylink_config.supported_interfaces); ++ + + /* If we have an xpcs, it defines which PHY interfaces are supported. */ + if (priv->hw->xpcs) +--- a/include/linux/stmmac.h ++++ b/include/linux/stmmac.h +@@ -229,6 +229,8 @@ struct plat_stmmacenet_data { + u8 tx_sched_algorithm; + struct stmmac_rxq_cfg rx_queues_cfg[MTL_MAX_RX_QUEUES]; + struct stmmac_txq_cfg tx_queues_cfg[MTL_MAX_TX_QUEUES]; ++ void (*get_interfaces)(struct stmmac_priv *priv, void *bsp_priv, ++ unsigned long *interfaces); + void (*fix_mac_speed)(void *priv, unsigned int speed, unsigned int mode); + int (*fix_soc_reset)(void *priv, void __iomem *ioaddr); + int (*serdes_powerup)(struct net_device *ndev, void *priv); diff --git a/target/linux/qualcommax/patches-6.12/0954-net-stmmac-Introduce-Qualcomm-IPQ5018-DWMAC-driver.patch b/target/linux/qualcommax/patches-6.12/0954-net-stmmac-Introduce-Qualcomm-IPQ5018-DWMAC-driver.patch new file mode 100644 index 00000000000..f0cf29a1b01 --- /dev/null +++ b/target/linux/qualcommax/patches-6.12/0954-net-stmmac-Introduce-Qualcomm-IPQ5018-DWMAC-driver.patch @@ -0,0 +1,27 @@ +--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig ++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig +@@ -78,6 +78,14 @@ config DWMAC_INGENIC + device driver. This driver is used on for the Ingenic SoCs + MAC ethernet controller. + ++config DWMAC_IPQ5018 ++ tristate "Qualcomm IPQ5018 DWMAC driver" ++ depends on OF && (ARCH_QCOM || COMPILE_TEST) ++ help ++ Support for ethernet controller on Qualcomm IPQ5018 SoCs. ++ ++ This selects the IPQ5018 SoC glue layer support for the stmmac driver. ++ + config DWMAC_IPQ806X + tristate "QCA IPQ806x DWMAC support" + default ARCH_QCOM +--- a/drivers/net/ethernet/stmicro/stmmac/Makefile ++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile +@@ -15,6 +15,7 @@ stmmac-$(CONFIG_STMMAC_SELFTESTS) += stm + obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o + obj-$(CONFIG_DWMAC_ANARION) += dwmac-anarion.o + obj-$(CONFIG_DWMAC_INGENIC) += dwmac-ingenic.o ++obj-$(CONFIG_DWMAC_IPQ5018) += dwmac-ipq5018.o + obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o + obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o + obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o