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 <george.moussalem@outlook.com> Link: https://github.com/openwrt/openwrt/pull/22381 Signed-off-by: Robert Marko <robimarko@gmail.com>
This commit is contained in:
committed by
Robert Marko
parent
bdb0b722b7
commit
b910cbfc0c
@@ -0,0 +1,199 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Qualcomm IPQ5018 DWMAC glue layer
|
||||
*
|
||||
* Copyright (C) 2026 The OpenWrt Project
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/pcs/pcs.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/stmmac.h>
|
||||
|
||||
#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");
|
||||
@@ -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 <george.moussalem@outlook.com>
|
||||
|
||||
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 <dt-bindings/clock/qcom,gcc-ipq5018.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
#include <dt-bindings/reset/qcom,gcc-ipq5018.h>
|
||||
|
||||
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 = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq";
|
||||
|
||||
phy-mode = "sgmii";
|
||||
pcs-handle = <&uniphy0>;
|
||||
};
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
From ca732e990fc8222a2d6782ae750304719e212fe8 Mon Sep 17 00:00:00 2001
|
||||
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
|
||||
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) <rmk+kernel@armlinux.org.uk>
|
||||
Link: https://patch.msgid.link/E1uASLn-0021Qd-Mi@rmk-PC.armlinux.org.uk
|
||||
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
|
||||
---
|
||||
.../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);
|
||||
+27
@@ -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
|
||||
Reference in New Issue
Block a user