mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
Merge branch 'net-stmmac-add-support-for-rzn1-gmac-devices'
Romain Gantois says: ==================== net: stmmac: Add support for RZN1 GMAC devices This is version seven of my series that adds support for a Gigabit Ethernet controller featured in the Renesas r9a06g032 SoC, of the RZ/N1 family. This GMAC device is based on a Synopsys IP and is compatible with the stmmac driver. My former colleague Clément Léger originally sent a series for this driver, but an issue in bringing up the PCS clock had blocked the upstreaming process. This issue has since been resolved by the following series: https://lore.kernel.org/all/20240326-rxc_bugfix-v6-0-24a74e5c761f@bootlin.com/ This series consists of a devicetree binding describing the RZN1 GMAC controller IP, a node for the GMAC1 device in the r9a06g032 SoC device tree, and the GMAC driver itself which is a glue layer in stmmac. There are also two patches by Russell that improve pcs initialization handling in stmmac. ==================== Link: https://lore.kernel.org/r/20240513-rzn1-gmac1-v7-0-6acf58b5440d@bootlin.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
0621be48a8
66
Documentation/devicetree/bindings/net/renesas,rzn1-gmac.yaml
Normal file
66
Documentation/devicetree/bindings/net/renesas,rzn1-gmac.yaml
Normal file
@ -0,0 +1,66 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/renesas,rzn1-gmac.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Renesas GMAC
|
||||
|
||||
maintainers:
|
||||
- Romain Gantois <romain.gantois@bootlin.com>
|
||||
|
||||
select:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- renesas,r9a06g032-gmac
|
||||
- renesas,rzn1-gmac
|
||||
required:
|
||||
- compatible
|
||||
|
||||
allOf:
|
||||
- $ref: snps,dwmac.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- renesas,r9a06g032-gmac
|
||||
- const: renesas,rzn1-gmac
|
||||
- const: snps,dwmac
|
||||
|
||||
pcs-handle:
|
||||
description:
|
||||
phandle pointing to a PCS sub-node compatible with
|
||||
renesas,rzn1-miic.yaml#
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/r9a06g032-sysctrl.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
|
||||
ethernet@44000000 {
|
||||
compatible = "renesas,r9a06g032-gmac", "renesas,rzn1-gmac", "snps,dwmac";
|
||||
reg = <0x44000000 0x2000>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
|
||||
interrupt-names = "macirq", "eth_wake_irq", "eth_lpi";
|
||||
clock-names = "stmmaceth";
|
||||
clocks = <&sysctrl R9A06G032_HCLK_GMAC0>;
|
||||
power-domains = <&sysctrl>;
|
||||
snps,multicast-filter-bins = <256>;
|
||||
snps,perfect-filter-entries = <128>;
|
||||
tx-fifo-depth = <2048>;
|
||||
rx-fifo-depth = <4096>;
|
||||
pcs-handle = <&mii_conv1>;
|
||||
phy-mode = "mii";
|
||||
};
|
||||
|
||||
...
|
@ -18874,6 +18874,12 @@ F: include/dt-bindings/net/pcs-rzn1-miic.h
|
||||
F: include/linux/pcs-rzn1-miic.h
|
||||
F: net/dsa/tag_rzn1_a5psw.c
|
||||
|
||||
RENESAS RZ/N1 DWMAC GLUE LAYER
|
||||
M: Romain Gantois <romain.gantois@bootlin.com>
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/net/renesas,rzn1-gmac.yaml
|
||||
F: drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
|
||||
|
||||
RENESAS RZ/N1 RTC CONTROLLER DRIVER
|
||||
M: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
L: linux-rtc@vger.kernel.org
|
||||
|
@ -142,6 +142,18 @@ config DWMAC_ROCKCHIP
|
||||
This selects the Rockchip RK3288 SoC glue layer support for
|
||||
the stmmac device driver.
|
||||
|
||||
config DWMAC_RZN1
|
||||
tristate "Renesas RZ/N1 dwmac support"
|
||||
default ARCH_RZN1
|
||||
depends on OF && (ARCH_RZN1 || COMPILE_TEST)
|
||||
select PCS_RZN1_MIIC
|
||||
help
|
||||
Support for Ethernet controller on Renesas RZ/N1 SoC family.
|
||||
|
||||
This selects the Renesas RZ/N1 SoC glue layer support for
|
||||
the stmmac device driver. This support can make use of a custom MII
|
||||
converter PCS device.
|
||||
|
||||
config DWMAC_SOCFPGA
|
||||
tristate "SOCFPGA dwmac support"
|
||||
default ARCH_INTEL_SOCFPGA
|
||||
|
@ -21,6 +21,7 @@ obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o
|
||||
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o
|
||||
obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o
|
||||
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
|
||||
obj-$(CONFIG_DWMAC_RZN1) += dwmac-rzn1.o
|
||||
obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
|
||||
obj-$(CONFIG_DWMAC_STARFIVE) += dwmac-starfive.o
|
||||
obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
|
||||
|
86
drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
Normal file
86
drivers/net/ethernet/stmicro/stmmac/dwmac-rzn1.c
Normal file
@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2024 Schneider-Electric
|
||||
*
|
||||
* Clément Léger <clement.leger@bootlin.com>
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
#include <linux/pcs-rzn1-miic.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "stmmac_platform.h"
|
||||
#include "stmmac.h"
|
||||
|
||||
static int rzn1_dwmac_pcs_init(struct stmmac_priv *priv)
|
||||
{
|
||||
struct device_node *np = priv->device->of_node;
|
||||
struct device_node *pcs_node;
|
||||
struct phylink_pcs *pcs;
|
||||
|
||||
pcs_node = of_parse_phandle(np, "pcs-handle", 0);
|
||||
|
||||
if (pcs_node) {
|
||||
pcs = miic_create(priv->device, pcs_node);
|
||||
of_node_put(pcs_node);
|
||||
if (IS_ERR(pcs))
|
||||
return PTR_ERR(pcs);
|
||||
|
||||
priv->hw->phylink_pcs = pcs;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzn1_dwmac_pcs_exit(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->hw->phylink_pcs)
|
||||
miic_destroy(priv->hw->phylink_pcs);
|
||||
}
|
||||
|
||||
static int rzn1_dwmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
struct stmmac_resources stmmac_res;
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = stmmac_get_platform_resources(pdev, &stmmac_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac);
|
||||
if (IS_ERR(plat_dat))
|
||||
return PTR_ERR(plat_dat);
|
||||
|
||||
plat_dat->bsp_priv = plat_dat;
|
||||
plat_dat->pcs_init = rzn1_dwmac_pcs_init;
|
||||
plat_dat->pcs_exit = rzn1_dwmac_pcs_exit;
|
||||
|
||||
ret = stmmac_dvr_probe(dev, plat_dat, &stmmac_res);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id rzn1_dwmac_match[] = {
|
||||
{ .compatible = "renesas,rzn1-gmac" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rzn1_dwmac_match);
|
||||
|
||||
static struct platform_driver rzn1_dwmac_driver = {
|
||||
.probe = rzn1_dwmac_probe,
|
||||
.remove_new = stmmac_pltfr_remove,
|
||||
.driver = {
|
||||
.name = "rzn1-dwmac",
|
||||
.of_match_table = rzn1_dwmac_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(rzn1_dwmac_driver);
|
||||
|
||||
MODULE_AUTHOR("Clément Léger <clement.leger@bootlin.com>");
|
||||
MODULE_DESCRIPTION("Renesas RZN1 DWMAC specific glue layer");
|
||||
MODULE_LICENSE("GPL");
|
@ -379,6 +379,56 @@ static int socfpga_gen10_set_phy_mode(struct socfpga_dwmac *dwmac)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int socfpga_dwmac_pcs_init(struct stmmac_priv *priv)
|
||||
{
|
||||
struct socfpga_dwmac *dwmac = priv->plat->bsp_priv;
|
||||
struct regmap_config pcs_regmap_cfg = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 16,
|
||||
.reg_shift = REGMAP_UPSHIFT(1),
|
||||
};
|
||||
struct mdio_regmap_config mrc;
|
||||
struct regmap *pcs_regmap;
|
||||
struct phylink_pcs *pcs;
|
||||
struct mii_bus *pcs_bus;
|
||||
|
||||
if (!dwmac->tse_pcs_base)
|
||||
return 0;
|
||||
|
||||
pcs_regmap = devm_regmap_init_mmio(priv->device, dwmac->tse_pcs_base,
|
||||
&pcs_regmap_cfg);
|
||||
if (IS_ERR(pcs_regmap))
|
||||
return PTR_ERR(pcs_regmap);
|
||||
|
||||
memset(&mrc, 0, sizeof(mrc));
|
||||
mrc.regmap = pcs_regmap;
|
||||
mrc.parent = priv->device;
|
||||
mrc.valid_addr = 0x0;
|
||||
mrc.autoscan = false;
|
||||
|
||||
/* Can't use ndev->name here because it will not have been initialised,
|
||||
* and in any case, the user can rename network interfaces at runtime.
|
||||
*/
|
||||
snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii",
|
||||
dev_name(priv->device));
|
||||
pcs_bus = devm_mdio_regmap_register(priv->device, &mrc);
|
||||
if (IS_ERR(pcs_bus))
|
||||
return PTR_ERR(pcs_bus);
|
||||
|
||||
pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
|
||||
if (IS_ERR(pcs))
|
||||
return PTR_ERR(pcs);
|
||||
|
||||
priv->hw->phylink_pcs = pcs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void socfpga_dwmac_pcs_exit(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->hw->phylink_pcs)
|
||||
lynx_pcs_destroy(priv->hw->phylink_pcs);
|
||||
}
|
||||
|
||||
static int socfpga_dwmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct plat_stmmacenet_data *plat_dat;
|
||||
@ -426,6 +476,8 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
|
||||
dwmac->ops = ops;
|
||||
plat_dat->bsp_priv = dwmac;
|
||||
plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
|
||||
plat_dat->pcs_init = socfpga_dwmac_pcs_init;
|
||||
plat_dat->pcs_exit = socfpga_dwmac_pcs_exit;
|
||||
|
||||
ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
|
||||
if (ret)
|
||||
@ -444,48 +496,6 @@ static int socfpga_dwmac_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err_dvr_remove;
|
||||
|
||||
/* Create a regmap for the PCS so that it can be used by the PCS driver,
|
||||
* if we have such a PCS
|
||||
*/
|
||||
if (dwmac->tse_pcs_base) {
|
||||
struct regmap_config pcs_regmap_cfg;
|
||||
struct mdio_regmap_config mrc;
|
||||
struct regmap *pcs_regmap;
|
||||
struct mii_bus *pcs_bus;
|
||||
|
||||
memset(&pcs_regmap_cfg, 0, sizeof(pcs_regmap_cfg));
|
||||
memset(&mrc, 0, sizeof(mrc));
|
||||
|
||||
pcs_regmap_cfg.reg_bits = 16;
|
||||
pcs_regmap_cfg.val_bits = 16;
|
||||
pcs_regmap_cfg.reg_shift = REGMAP_UPSHIFT(1);
|
||||
|
||||
pcs_regmap = devm_regmap_init_mmio(&pdev->dev, dwmac->tse_pcs_base,
|
||||
&pcs_regmap_cfg);
|
||||
if (IS_ERR(pcs_regmap)) {
|
||||
ret = PTR_ERR(pcs_regmap);
|
||||
goto err_dvr_remove;
|
||||
}
|
||||
|
||||
mrc.regmap = pcs_regmap;
|
||||
mrc.parent = &pdev->dev;
|
||||
mrc.valid_addr = 0x0;
|
||||
mrc.autoscan = false;
|
||||
|
||||
snprintf(mrc.name, MII_BUS_ID_SIZE, "%s-pcs-mii", ndev->name);
|
||||
pcs_bus = devm_mdio_regmap_register(&pdev->dev, &mrc);
|
||||
if (IS_ERR(pcs_bus)) {
|
||||
ret = PTR_ERR(pcs_bus);
|
||||
goto err_dvr_remove;
|
||||
}
|
||||
|
||||
stpriv->hw->phylink_pcs = lynx_pcs_create_mdiodev(pcs_bus, 0);
|
||||
if (IS_ERR(stpriv->hw->phylink_pcs)) {
|
||||
ret = PTR_ERR(stpriv->hw->phylink_pcs);
|
||||
goto err_dvr_remove;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_dvr_remove:
|
||||
@ -494,17 +504,6 @@ err_dvr_remove:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void socfpga_dwmac_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct net_device *ndev = platform_get_drvdata(pdev);
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
struct phylink_pcs *pcs = priv->hw->phylink_pcs;
|
||||
|
||||
stmmac_pltfr_remove(pdev);
|
||||
|
||||
lynx_pcs_destroy(pcs);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int socfpga_dwmac_resume(struct device *dev)
|
||||
{
|
||||
@ -576,7 +575,7 @@ MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
|
||||
|
||||
static struct platform_driver socfpga_dwmac_driver = {
|
||||
.probe = socfpga_dwmac_probe,
|
||||
.remove_new = socfpga_dwmac_remove,
|
||||
.remove_new = stmmac_pltfr_remove,
|
||||
.driver = {
|
||||
.name = "socfpga-dwmac",
|
||||
.pm = &socfpga_dwmac_pm_ops,
|
||||
|
@ -360,7 +360,8 @@ enum stmmac_state {
|
||||
int stmmac_mdio_unregister(struct net_device *ndev);
|
||||
int stmmac_mdio_register(struct net_device *ndev);
|
||||
int stmmac_mdio_reset(struct mii_bus *mii);
|
||||
int stmmac_xpcs_setup(struct mii_bus *mii);
|
||||
int stmmac_pcs_setup(struct net_device *ndev);
|
||||
void stmmac_pcs_clean(struct net_device *ndev);
|
||||
void stmmac_set_ethtool_ops(struct net_device *netdev);
|
||||
|
||||
int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags);
|
||||
|
@ -7754,11 +7754,9 @@ int stmmac_dvr_probe(struct device *device,
|
||||
if (priv->plat->speed_mode_2500)
|
||||
priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv);
|
||||
|
||||
if (priv->plat->mdio_bus_data && priv->plat->mdio_bus_data->has_xpcs) {
|
||||
ret = stmmac_xpcs_setup(priv->mii);
|
||||
if (ret)
|
||||
goto error_xpcs_setup;
|
||||
}
|
||||
ret = stmmac_pcs_setup(ndev);
|
||||
if (ret)
|
||||
goto error_pcs_setup;
|
||||
|
||||
ret = stmmac_phy_setup(priv);
|
||||
if (ret) {
|
||||
@ -7789,8 +7787,9 @@ int stmmac_dvr_probe(struct device *device,
|
||||
|
||||
error_netdev_register:
|
||||
phylink_destroy(priv->phylink);
|
||||
error_xpcs_setup:
|
||||
error_phy_setup:
|
||||
stmmac_pcs_clean(ndev);
|
||||
error_pcs_setup:
|
||||
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
||||
priv->hw->pcs != STMMAC_PCS_RTBI)
|
||||
stmmac_mdio_unregister(ndev);
|
||||
@ -7832,6 +7831,9 @@ void stmmac_dvr_remove(struct device *dev)
|
||||
if (priv->plat->stmmac_rst)
|
||||
reset_control_assert(priv->plat->stmmac_rst);
|
||||
reset_control_assert(priv->plat->stmmac_ahb_rst);
|
||||
|
||||
stmmac_pcs_clean(ndev);
|
||||
|
||||
if (priv->hw->pcs != STMMAC_PCS_TBI &&
|
||||
priv->hw->pcs != STMMAC_PCS_RTBI)
|
||||
stmmac_mdio_unregister(ndev);
|
||||
|
@ -495,34 +495,57 @@ int stmmac_mdio_reset(struct mii_bus *bus)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stmmac_xpcs_setup(struct mii_bus *bus)
|
||||
int stmmac_pcs_setup(struct net_device *ndev)
|
||||
{
|
||||
struct net_device *ndev = bus->priv;
|
||||
struct dw_xpcs *xpcs = NULL;
|
||||
struct stmmac_priv *priv;
|
||||
struct dw_xpcs *xpcs;
|
||||
int ret = -ENODEV;
|
||||
int mode, addr;
|
||||
|
||||
priv = netdev_priv(ndev);
|
||||
mode = priv->plat->phy_interface;
|
||||
|
||||
/* Try to probe the XPCS by scanning all addresses. */
|
||||
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
|
||||
xpcs = xpcs_create_mdiodev(bus, addr, mode);
|
||||
if (IS_ERR(xpcs))
|
||||
continue;
|
||||
if (priv->plat->pcs_init) {
|
||||
ret = priv->plat->pcs_init(priv);
|
||||
} else if (priv->plat->mdio_bus_data &&
|
||||
priv->plat->mdio_bus_data->has_xpcs) {
|
||||
/* Try to probe the XPCS by scanning all addresses */
|
||||
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
|
||||
xpcs = xpcs_create_mdiodev(priv->mii, addr, mode);
|
||||
if (IS_ERR(xpcs))
|
||||
continue;
|
||||
|
||||
priv->hw->xpcs = xpcs;
|
||||
break;
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!priv->hw->xpcs) {
|
||||
if (ret) {
|
||||
dev_warn(priv->device, "No xPCS found\n");
|
||||
return -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->hw->xpcs = xpcs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stmmac_pcs_clean(struct net_device *ndev)
|
||||
{
|
||||
struct stmmac_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (priv->plat->pcs_exit)
|
||||
priv->plat->pcs_exit(priv);
|
||||
|
||||
if (!priv->hw->xpcs)
|
||||
return;
|
||||
|
||||
xpcs_destroy(priv->hw->xpcs);
|
||||
priv->hw->xpcs = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_mdio_register
|
||||
* @ndev: net device structure
|
||||
@ -679,9 +702,6 @@ int stmmac_mdio_unregister(struct net_device *ndev)
|
||||
if (!priv->mii)
|
||||
return 0;
|
||||
|
||||
if (priv->hw->xpcs)
|
||||
xpcs_destroy(priv->hw->xpcs);
|
||||
|
||||
mdiobus_unregister(priv->mii);
|
||||
priv->mii->priv = NULL;
|
||||
mdiobus_free(priv->mii);
|
||||
|
@ -285,6 +285,8 @@ struct plat_stmmacenet_data {
|
||||
int (*crosststamp)(ktime_t *device, struct system_counterval_t *system,
|
||||
void *ctx);
|
||||
void (*dump_debug_regs)(void *priv);
|
||||
int (*pcs_init)(struct stmmac_priv *priv);
|
||||
void (*pcs_exit)(struct stmmac_priv *priv);
|
||||
void *bsp_priv;
|
||||
struct clk *stmmac_clk;
|
||||
struct clk *pclk;
|
||||
|
Loading…
x
Reference in New Issue
Block a user