diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro')
72 files changed, 4434 insertions, 4347 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 3c820ef56775..907fe2e927f0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -3,12 +3,14 @@ config STMMAC_ETH tristate "STMicroelectronics Multi-Gigabit Ethernet driver" depends on HAS_IOMEM && HAS_DMA depends on PTP_1588_CLOCK_OPTIONAL + depends on ETHTOOL_NETLINK select MII select PCS_XPCS select PAGE_POOL select PHYLINK select CRC32 select RESET_CONTROLLER + select NET_DEVLINK help This is the driver for the Ethernet IPs built around a Synopsys IP Core. @@ -66,6 +68,15 @@ config DWMAC_ANARION This selects the Anarion SoC glue layer support for the stmmac driver. +config DWMAC_EIC7700 + tristate "Support for Eswin eic7700 ethernet driver" + depends on OF && HAS_DMA && ARCH_ESWIN || COMPILE_TEST + help + This driver supports the Eswin EIC7700 Ethernet controller, + which integrates Synopsys DesignWare QoS features. It enables + high-speed networking with DMA acceleration and is optimized + for embedded systems. + config DWMAC_INGENIC tristate "Ingenic MAC support" default MACH_INGENIC @@ -131,6 +142,19 @@ config DWMAC_QCOM_ETHQOS This selects the Qualcomm ETHQOS glue layer support for the stmmac device driver. +config DWMAC_RENESAS_GBETH + tristate "Renesas RZ/V2H(P) GBETH and RZ/T2H, RZ/N2H GMAC support" + default ARCH_RENESAS + depends on OF && (ARCH_RENESAS || COMPILE_TEST) + select PCS_RZN1_MIIC + help + Support for Gigabit Ethernet Interface (GBETH)/ Ethernet MAC (GMAC) + on Renesas SoCs. + + This selects Renesas SoC glue layer support for the stmmac device + driver. This driver is used for the RZ/V2H(P) family, RZ/T2H and + RZ/N2H SoCs. + config DWMAC_ROCKCHIP tristate "Rockchip dwmac support" default ARCH_ROCKCHIP @@ -251,6 +275,18 @@ config DWMAC_SUN8I stmmac device driver. This driver is used for H3/A83T/A64 EMAC ethernet controller. +config DWMAC_SUN55I + tristate "Allwinner sun55i GMAC200 support" + default ARCH_SUNXI + depends on OF && (ARCH_SUNXI || COMPILE_TEST) + select MDIO_BUS_MUX + help + Support for Allwinner A523/T527 GMAC200 ethernet controllers. + + This selects Allwinner SoC glue layer support for the + stmmac device driver. This driver is used for A523/T527 + GMAC200 ethernet controller. + config DWMAC_THEAD tristate "T-HEAD dwmac support" depends on OF && (ARCH_THEAD || COMPILE_TEST) @@ -313,6 +349,11 @@ config DWMAC_VISCONTI endif +config STMMAC_LIBPCI + tristate + help + This option enables the PCI bus helpers for the stmmac driver. + config DWMAC_INTEL tristate "Intel GMAC support" default X86 @@ -326,16 +367,18 @@ config DWMAC_INTEL config DWMAC_LOONGSON tristate "Loongson PCI DWMAC support" default MACH_LOONGSON64 - depends on (MACH_LOONGSON64 || COMPILE_TEST) && STMMAC_ETH && PCI + depends on (MACH_LOONGSON64 || COMPILE_TEST) && PCI depends on COMMON_CLK + select STMMAC_LIBPCI help This selects the LOONGSON PCI bus support for the stmmac driver, Support for ethernet controller on Loongson-2K1000 SoC and LS7A1000 bridge. config STMMAC_PCI tristate "STMMAC PCI bus support" - depends on STMMAC_ETH && PCI + depends on PCI depends on COMMON_CLK + select STMMAC_LIBPCI help This selects the platform specific bus support for the stmmac driver. This driver was tested on XLINX XC2V3000 FF1152AMT0221 diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 594883fb4164..7bf528731034 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -6,20 +6,22 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \ stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \ - stmmac_xdp.o stmmac_est.o stmmac_fpe.o \ - $(stmmac-y) + stmmac_xdp.o stmmac_est.o stmmac_fpe.o stmmac_vlan.o \ + stmmac_pcs.o $(stmmac-y) 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_EIC7700) += dwmac-eic7700.o obj-$(CONFIG_DWMAC_INGENIC) += dwmac-ingenic.o obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o 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_RENESAS_GBETH) += dwmac-renesas-gbeth.o obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o obj-$(CONFIG_DWMAC_RZN1) += dwmac-rzn1.o obj-$(CONFIG_DWMAC_S32) += dwmac-s32.o @@ -30,6 +32,7 @@ obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o +obj-$(CONFIG_DWMAC_SUN55I) += dwmac-sun55i.o obj-$(CONFIG_DWMAC_THEAD) += dwmac-thead.o obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o obj-$(CONFIG_DWMAC_INTEL_PLAT) += dwmac-intel-plat.o @@ -41,6 +44,7 @@ obj-$(CONFIG_DWMAC_VISCONTI) += dwmac-visconti.o stmmac-platform-objs:= stmmac_platform.o dwmac-altr-socfpga-objs := dwmac-socfpga.o +obj-$(CONFIG_STMMAC_LIBPCI) += stmmac_libpci.o obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o obj-$(CONFIG_DWMAC_INTEL) += dwmac-intel.o obj-$(CONFIG_DWMAC_LOONGSON) += dwmac-loongson.o diff --git a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c index fb55efd52240..120a009c9992 100644 --- a/drivers/net/ethernet/stmicro/stmmac/chain_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/chain_mode.c @@ -83,14 +83,13 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb, return entry; } -static unsigned int is_jumbo_frm(int len, int enh_desc) +static bool is_jumbo_frm(unsigned int len, bool enh_desc) { - unsigned int ret = 0; + bool ret = false; if ((enh_desc && (len > BUF_SIZE_8KiB)) || - (!enh_desc && (len > BUF_SIZE_2KiB))) { - ret = 1; - } + (!enh_desc && (len > BUF_SIZE_2KiB))) + ret = true; return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 412b07e77945..49df46be3669 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -26,6 +26,9 @@ #include "hwif.h" #include "mmc.h" +#define DWMAC_SNPSVER GENMASK_U32(7, 0) +#define DWMAC_USERVER GENMASK_U32(15, 8) + /* Synopsys Core versions */ #define DWMAC_CORE_3_40 0x34 #define DWMAC_CORE_3_50 0x35 @@ -43,6 +46,11 @@ #define DWXGMAC_ID 0x76 #define DWXLGMAC_ID 0x27 +static inline bool dwmac_is_xmac(enum dwmac_core_type core_type) +{ + return core_type == DWMAC_CORE_GMAC4 || core_type == DWMAC_CORE_XGMAC; +} + #define STMMAC_CHAN0 0 /* Always supported and default for all chips */ /* TX and RX Descriptor Length, these need to be power of two. @@ -192,9 +200,6 @@ struct stmmac_extra_stats { unsigned long irq_pcs_ane_n; unsigned long irq_pcs_link_n; unsigned long irq_rgmii_n; - unsigned long pcs_link; - unsigned long pcs_duplex; - unsigned long pcs_speed; /* debug register */ unsigned long mtl_tx_status_fifo_full; unsigned long mtl_tx_fifo_not_empty; @@ -228,6 +233,7 @@ struct stmmac_extra_stats { unsigned long mtl_est_btrlm; unsigned long max_sdu_txq_drop[MTL_MAX_TX_QUEUES]; unsigned long mtl_est_txq_hlbf[MTL_MAX_TX_QUEUES]; + unsigned long mtl_est_txq_hlbs[MTL_MAX_TX_QUEUES]; /* per queue statistics */ struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; @@ -272,7 +278,6 @@ struct stmmac_safety_stats { #define FLOW_AUTO (FLOW_TX | FLOW_RX) /* PCS defines */ -#define STMMAC_PCS_RGMII (1 << 0) #define STMMAC_PCS_SGMII (1 << 1) #define SF_DMA_MODE 1 /* DMA STORE-AND-FORWARD Operation Mode */ @@ -308,6 +313,16 @@ struct stmmac_safety_stats { #define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY iface */ #define DEFAULT_DMA_PBL 8 +/* phy_intf_sel_i and ACTPHYIF encodings */ +#define PHY_INTF_SEL_GMII_MII 0 +#define PHY_INTF_SEL_RGMII 1 +#define PHY_INTF_SEL_SGMII 2 +#define PHY_INTF_SEL_TBI 3 +#define PHY_INTF_SEL_RMII 4 +#define PHY_INTF_SEL_RTBI 5 +#define PHY_INTF_SEL_SMII 6 +#define PHY_INTF_SEL_REVMII 7 + /* MSI defines */ #define STMMAC_MSI_VEC_MAX 32 @@ -396,17 +411,6 @@ enum request_irq_err { #define CORE_IRQ_MTL_RX_OVERFLOW BIT(8) -/* Physical Coding Sublayer */ -struct rgmii_adv { - unsigned int pause; - unsigned int duplex; - unsigned int lp_pause; - unsigned int lp_duplex; -}; - -#define STMMAC_PCS_PAUSE 1 -#define STMMAC_PCS_ASYM_PAUSE 2 - /* DMA HW capabilities */ struct dma_features { unsigned int mbps_10_100; @@ -544,6 +548,19 @@ struct dma_features { #define LPI_CTRL_STATUS_TLPIEX BIT(1) /* Transmit LPI Exit */ #define LPI_CTRL_STATUS_TLPIEN BIT(0) /* Transmit LPI Entry */ +/* Common definitions for AXI Master Bus Mode */ +#define DMA_AXI_AAL BIT(12) +#define DMA_AXI_BLEN256 BIT(7) +#define DMA_AXI_BLEN128 BIT(6) +#define DMA_AXI_BLEN64 BIT(5) +#define DMA_AXI_BLEN32 BIT(4) +#define DMA_AXI_BLEN16 BIT(3) +#define DMA_AXI_BLEN8 BIT(2) +#define DMA_AXI_BLEN4 BIT(1) +#define DMA_AXI_BLEN_MASK GENMASK(7, 1) + +void stmmac_axi_blen_to_mask(u32 *regval, const u32 *blen, size_t len); + #define STMMAC_CHAIN_MODE 0x1 #define STMMAC_RING_MODE 0x2 @@ -602,6 +619,7 @@ struct mac_device_info { const struct stmmac_tc_ops *tc; const struct stmmac_mmc_ops *mmc; const struct stmmac_est_ops *est; + const struct stmmac_vlan_ops *vlan; struct dw_xpcs *xpcs; struct phylink_pcs *phylink_pcs; struct mii_regs mii; /* MII register Addresses */ @@ -612,14 +630,18 @@ struct mac_device_info { unsigned int mcast_bits_log2; unsigned int rx_csum; unsigned int pcs; - unsigned int pmt; - unsigned int ps; unsigned int xlgmac; unsigned int num_vlan; u32 vlan_filter[32]; bool vlan_fail_q_en; u8 vlan_fail_q; bool hw_vlan_en; + bool reverse_sgmii_enable; + + /* This spinlock protects read-modify-write of the interrupt + * mask/enable registers. + */ + spinlock_t irq_ctrl_lock; }; struct stmmac_rx_routing { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c index 37fe7c288878..5e0fc31762d9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-anarion.c @@ -34,7 +34,7 @@ static void gmac_write_reg(struct anarion_gmac *gmac, uint8_t reg, uint32_t val) writel(val, gmac->ctl_block + reg); } -static int anarion_gmac_init(struct platform_device *pdev, void *priv) +static int anarion_gmac_init(struct device *dev, void *priv) { uint32_t sw_config; struct anarion_gmac *gmac = priv; @@ -52,7 +52,7 @@ static int anarion_gmac_init(struct platform_device *pdev, void *priv) return 0; } -static void anarion_gmac_exit(struct platform_device *pdev, void *priv) +static void anarion_gmac_exit(struct device *dev, void *priv) { struct anarion_gmac *gmac = priv; @@ -65,13 +65,12 @@ anarion_config_dt(struct platform_device *pdev, { struct anarion_gmac *gmac; void __iomem *ctl_block; - int err; ctl_block = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(ctl_block)) { - err = PTR_ERR(ctl_block); - dev_err(&pdev->dev, "Cannot get reset region (%d)!\n", err); - return ERR_PTR(err); + dev_err(&pdev->dev, "Cannot get reset region (%pe)!\n", + ctl_block); + return ERR_CAST(ctl_block); } gmac = devm_kzalloc(&pdev->dev, sizeof(*gmac), GFP_KERNEL); @@ -80,17 +79,11 @@ anarion_config_dt(struct platform_device *pdev, gmac->ctl_block = ctl_block; - switch (plat_dat->phy_interface) { - case PHY_INTERFACE_MODE_RGMII: - fallthrough; - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: + if (phy_interface_mode_is_rgmii(plat_dat->phy_interface)) { gmac->phy_intf_sel = GMAC_CONFIG_INTF_RGMII; - break; - default: - dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", - plat_dat->phy_interface); + } else { + dev_err(&pdev->dev, "Unsupported phy-mode (%s)\n", + phy_modes(plat_dat->phy_interface)); return ERR_PTR(-ENOTSUPP); } @@ -118,10 +111,9 @@ static int anarion_dwmac_probe(struct platform_device *pdev) plat_dat->init = anarion_gmac_init; plat_dat->exit = anarion_gmac_exit; - anarion_gmac_init(pdev, gmac); plat_dat->bsp_priv = gmac; - return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } static const struct of_device_id anarion_dwmac_match[] = { @@ -132,7 +124,6 @@ MODULE_DEVICE_TABLE(of, anarion_dwmac_match); static struct platform_driver anarion_dwmac_driver = { .probe = anarion_dwmac_probe, - .remove = stmmac_pltfr_remove, .driver = { .name = "anarion-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c index cd431f84f34f..d043bad4a862 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-dwc-qos-eth.c @@ -29,28 +29,15 @@ struct tegra_eqos { void __iomem *regs; struct reset_control *rst; - struct clk *clk_slave; struct gpio_desc *reset; }; -static struct clk *dwc_eth_find_clk(struct plat_stmmacenet_data *plat_dat, - const char *name) -{ - for (int i = 0; i < plat_dat->num_clks; i++) - if (strcmp(plat_dat->clks[i].id, name) == 0) - return plat_dat->clks[i].clk; - - return NULL; -} - static int dwc_eth_dwmac_config_dt(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat) { struct device *dev = &pdev->dev; u32 burst_map = 0; - u32 bit_index = 0; - u32 a_index = 0; if (!plat_dat->axi) { plat_dat->axi = devm_kzalloc(&pdev->dev, @@ -94,33 +81,11 @@ static int dwc_eth_dwmac_config_dt(struct platform_device *pdev, } device_property_read_u32(dev, "snps,burst-map", &burst_map); - /* converts burst-map bitmask to burst array */ - for (bit_index = 0; bit_index < 7; bit_index++) { - if (burst_map & (1 << bit_index)) { - switch (bit_index) { - case 0: - plat_dat->axi->axi_blen[a_index] = 4; break; - case 1: - plat_dat->axi->axi_blen[a_index] = 8; break; - case 2: - plat_dat->axi->axi_blen[a_index] = 16; break; - case 3: - plat_dat->axi->axi_blen[a_index] = 32; break; - case 4: - plat_dat->axi->axi_blen[a_index] = 64; break; - case 5: - plat_dat->axi->axi_blen[a_index] = 128; break; - case 6: - plat_dat->axi->axi_blen[a_index] = 256; break; - default: - break; - } - a_index++; - } - } + plat_dat->axi->axi_blen_regval = FIELD_PREP(DMA_AXI_BLEN_MASK, + burst_map); /* dwc-qos needs GMAC4, AAL, TSO and PMT */ - plat_dat->has_gmac4 = 1; + plat_dat->core_type = DWMAC_CORE_GMAC4; plat_dat->dma_cfg->aal = 1; plat_dat->flags |= STMMAC_FLAG_TSO_EN; plat_dat->pmt = 1; @@ -132,7 +97,7 @@ static int dwc_qos_probe(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat, struct stmmac_resources *stmmac_res) { - plat_dat->pclk = dwc_eth_find_clk(plat_dat, "phy_ref_clk"); + plat_dat->pclk = stmmac_pltfr_find_clk(plat_dat, "phy_ref_clk"); return 0; } @@ -147,10 +112,11 @@ static int dwc_qos_probe(struct platform_device *pdev, #define AUTO_CAL_STATUS 0x880c #define AUTO_CAL_STATUS_ACTIVE BIT(31) -static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) +static void tegra_eqos_fix_speed(void *bsp_priv, int speed, unsigned int mode) { - struct tegra_eqos *eqos = priv; + struct tegra_eqos *eqos = bsp_priv; bool needs_calibration = false; + struct stmmac_priv *priv; u32 value; int err; @@ -169,6 +135,11 @@ static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) } if (needs_calibration) { + priv = netdev_priv(dev_get_drvdata(eqos->dev)); + + /* Calibration should be done with the MDIO bus idle */ + stmmac_mdio_lock(priv); + /* calibrate */ value = readl(eqos->regs + SDMEMCOMPPADCTRL); value |= SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD; @@ -202,6 +173,8 @@ static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) value = readl(eqos->regs + SDMEMCOMPPADCTRL); value &= ~SDMEMCOMPPADCTRL_PAD_E_INPUT_OR_E_PWRD; writel(value, eqos->regs + SDMEMCOMPPADCTRL); + + stmmac_mdio_unlock(priv); } else { value = readl(eqos->regs + AUTO_CAL_CONFIG); value &= ~AUTO_CAL_CONFIG_ENABLE; @@ -209,20 +182,6 @@ static void tegra_eqos_fix_speed(void *priv, int speed, unsigned int mode) } } -static int tegra_eqos_init(struct platform_device *pdev, void *priv) -{ - struct tegra_eqos *eqos = priv; - unsigned long rate; - u32 value; - - rate = clk_get_rate(eqos->clk_slave); - - value = (rate / 1000000) - 1; - writel(value, eqos->regs + GMAC_1US_TIC_COUNTER); - - return 0; -} - static int tegra_eqos_probe(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat, struct stmmac_resources *res) @@ -237,12 +196,11 @@ static int tegra_eqos_probe(struct platform_device *pdev, eqos->dev = &pdev->dev; eqos->regs = res->addr; - eqos->clk_slave = plat_dat->stmmac_clk; if (!is_of_node(dev->fwnode)) goto bypass_clk_reset_gpio; - plat_dat->clk_tx_i = dwc_eth_find_clk(plat_dat, "tx"); + plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx"); eqos->reset = devm_gpiod_get(&pdev->dev, "phy-reset", GPIOD_OUT_HIGH); if (IS_ERR(eqos->reset)) { @@ -277,17 +235,13 @@ static int tegra_eqos_probe(struct platform_device *pdev, bypass_clk_reset_gpio: plat_dat->fix_mac_speed = tegra_eqos_fix_speed; plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; - plat_dat->init = tegra_eqos_init; plat_dat->bsp_priv = eqos; - plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE; - - err = tegra_eqos_init(pdev, eqos); - if (err < 0) - goto reset; + plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE | + STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP | + STMMAC_FLAG_USE_PHY_WOL; return 0; -reset: - reset_control_assert(eqos->rst); + reset_phy: gpiod_set_value(eqos->reset, 1); @@ -353,23 +307,18 @@ static int dwc_eth_dwmac_probe(struct platform_device *pdev) if (IS_ERR(plat_dat)) return PTR_ERR(plat_dat); - ret = devm_clk_bulk_get_all(&pdev->dev, &plat_dat->clks); + ret = devm_clk_bulk_get_all_enabled(&pdev->dev, &plat_dat->clks); if (ret < 0) - return dev_err_probe(&pdev->dev, ret, "Failed to retrieve all required clocks\n"); + return dev_err_probe(&pdev->dev, ret, "Failed to retrieve and enable all required clocks\n"); plat_dat->num_clks = ret; - ret = clk_bulk_prepare_enable(plat_dat->num_clks, plat_dat->clks); - if (ret) - return dev_err_probe(&pdev->dev, ret, "Failed to enable clocks\n"); - - plat_dat->stmmac_clk = dwc_eth_find_clk(plat_dat, - data->stmmac_clk_name); + plat_dat->stmmac_clk = stmmac_pltfr_find_clk(plat_dat, + data->stmmac_clk_name); if (data->probe) ret = data->probe(pdev, plat_dat, &stmmac_res); if (ret < 0) { dev_err_probe(&pdev->dev, ret, "failed to probe subdriver\n"); - clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks); return ret; } @@ -393,15 +342,11 @@ remove: static void dwc_eth_dwmac_remove(struct platform_device *pdev) { const struct dwc_eth_dwmac_data *data = device_get_match_data(&pdev->dev); - struct plat_stmmacenet_data *plat_dat = dev_get_platdata(&pdev->dev); stmmac_dvr_remove(&pdev->dev); if (data->remove) data->remove(pdev); - - if (plat_dat) - clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks); } static const struct of_device_id dwc_eth_dwmac_match[] = { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c new file mode 100644 index 000000000000..bcb8e000e720 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Eswin DWC Ethernet linux driver + * + * Copyright 2025, Beijing ESWIN Computing Technology Co., Ltd. + * + * Authors: + * Zhi Li <lizhi2@eswincomputing.com> + * Shuang Liang <liangshuang@eswincomputing.com> + * Shangjuan Wei <weishangjuan@eswincomputing.com> + */ + +#include <linux/platform_device.h> +#include <linux/mfd/syscon.h> +#include <linux/pm_runtime.h> +#include <linux/stmmac.h> +#include <linux/regmap.h> +#include <linux/of.h> + +#include "stmmac_platform.h" + +/* eth_phy_ctrl_offset eth0:0x100 */ +#define EIC7700_ETH_TX_CLK_SEL BIT(16) +#define EIC7700_ETH_PHY_INTF_SELI BIT(0) + +/* eth_axi_lp_ctrl_offset eth0:0x108 */ +#define EIC7700_ETH_CSYSREQ_VAL BIT(0) + +/* + * TX/RX Clock Delay Bit Masks: + * - TX Delay: bits [14:8] — TX_CLK delay (unit: 0.1ns per bit) + * - RX Delay: bits [30:24] — RX_CLK delay (unit: 0.1ns per bit) + */ +#define EIC7700_ETH_TX_ADJ_DELAY GENMASK(14, 8) +#define EIC7700_ETH_RX_ADJ_DELAY GENMASK(30, 24) + +#define EIC7700_MAX_DELAY_UNIT 0x7F + +static const char * const eic7700_clk_names[] = { + "tx", "axi", "cfg", +}; + +struct eic7700_qos_priv { + struct plat_stmmacenet_data *plat_dat; +}; + +static int eic7700_clks_config(void *priv, bool enabled) +{ + struct eic7700_qos_priv *dwc = (struct eic7700_qos_priv *)priv; + struct plat_stmmacenet_data *plat = dwc->plat_dat; + int ret = 0; + + if (enabled) + ret = clk_bulk_prepare_enable(plat->num_clks, plat->clks); + else + clk_bulk_disable_unprepare(plat->num_clks, plat->clks); + + return ret; +} + +static int eic7700_dwmac_init(struct device *dev, void *priv) +{ + struct eic7700_qos_priv *dwc = priv; + + return eic7700_clks_config(dwc, true); +} + +static void eic7700_dwmac_exit(struct device *dev, void *priv) +{ + struct eic7700_qos_priv *dwc = priv; + + eic7700_clks_config(dwc, false); +} + +static int eic7700_dwmac_suspend(struct device *dev, void *priv) +{ + return pm_runtime_force_suspend(dev); +} + +static int eic7700_dwmac_resume(struct device *dev, void *priv) +{ + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + dev_err(dev, "%s failed: %d\n", __func__, ret); + + return ret; +} + +static int eic7700_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct eic7700_qos_priv *dwc_priv; + struct regmap *eic7700_hsp_regmap; + u32 eth_axi_lp_ctrl_offset; + u32 eth_phy_ctrl_offset; + u32 eth_phy_ctrl_regset; + u32 eth_rxd_dly_offset; + u32 eth_dly_param = 0; + u32 delay_ps; + int i, ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to get resources\n"); + + plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR(plat_dat)) + return dev_err_probe(&pdev->dev, PTR_ERR(plat_dat), + "dt configuration failed\n"); + + dwc_priv = devm_kzalloc(&pdev->dev, sizeof(*dwc_priv), GFP_KERNEL); + if (!dwc_priv) + return -ENOMEM; + + /* Read rx-internal-delay-ps and update rx_clk delay */ + if (!of_property_read_u32(pdev->dev.of_node, + "rx-internal-delay-ps", &delay_ps)) { + u32 val = min(delay_ps / 100, EIC7700_MAX_DELAY_UNIT); + + eth_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY; + eth_dly_param |= FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val); + } else { + return dev_err_probe(&pdev->dev, -EINVAL, + "missing required property rx-internal-delay-ps\n"); + } + + /* Read tx-internal-delay-ps and update tx_clk delay */ + if (!of_property_read_u32(pdev->dev.of_node, + "tx-internal-delay-ps", &delay_ps)) { + u32 val = min(delay_ps / 100, EIC7700_MAX_DELAY_UNIT); + + eth_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY; + eth_dly_param |= FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val); + } else { + return dev_err_probe(&pdev->dev, -EINVAL, + "missing required property tx-internal-delay-ps\n"); + } + + eic7700_hsp_regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "eswin,hsp-sp-csr"); + if (IS_ERR(eic7700_hsp_regmap)) + return dev_err_probe(&pdev->dev, + PTR_ERR(eic7700_hsp_regmap), + "Failed to get hsp-sp-csr regmap\n"); + + ret = of_property_read_u32_index(pdev->dev.of_node, + "eswin,hsp-sp-csr", + 1, ð_phy_ctrl_offset); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't get eth_phy_ctrl_offset\n"); + + regmap_read(eic7700_hsp_regmap, eth_phy_ctrl_offset, + ð_phy_ctrl_regset); + eth_phy_ctrl_regset |= + (EIC7700_ETH_TX_CLK_SEL | EIC7700_ETH_PHY_INTF_SELI); + regmap_write(eic7700_hsp_regmap, eth_phy_ctrl_offset, + eth_phy_ctrl_regset); + + ret = of_property_read_u32_index(pdev->dev.of_node, + "eswin,hsp-sp-csr", + 2, ð_axi_lp_ctrl_offset); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't get eth_axi_lp_ctrl_offset\n"); + + regmap_write(eic7700_hsp_regmap, eth_axi_lp_ctrl_offset, + EIC7700_ETH_CSYSREQ_VAL); + + ret = of_property_read_u32_index(pdev->dev.of_node, + "eswin,hsp-sp-csr", + 3, ð_rxd_dly_offset); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't get eth_rxd_dly_offset\n"); + + regmap_write(eic7700_hsp_regmap, eth_rxd_dly_offset, + eth_dly_param); + + plat_dat->num_clks = ARRAY_SIZE(eic7700_clk_names); + plat_dat->clks = devm_kcalloc(&pdev->dev, + plat_dat->num_clks, + sizeof(*plat_dat->clks), + GFP_KERNEL); + if (!plat_dat->clks) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(eic7700_clk_names); i++) + plat_dat->clks[i].id = eic7700_clk_names[i]; + + ret = devm_clk_bulk_get_optional(&pdev->dev, + plat_dat->num_clks, + plat_dat->clks); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "Failed to get clocks\n"); + + plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx"); + plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; + plat_dat->clks_config = eic7700_clks_config; + plat_dat->bsp_priv = dwc_priv; + dwc_priv->plat_dat = plat_dat; + plat_dat->init = eic7700_dwmac_init; + plat_dat->exit = eic7700_dwmac_exit; + plat_dat->suspend = eic7700_dwmac_suspend; + plat_dat->resume = eic7700_dwmac_resume; + + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); +} + +static const struct of_device_id eic7700_dwmac_match[] = { + { .compatible = "eswin,eic7700-qos-eth" }, + { } +}; +MODULE_DEVICE_TABLE(of, eic7700_dwmac_match); + +static struct platform_driver eic7700_dwmac_driver = { + .probe = eic7700_dwmac_probe, + .driver = { + .name = "eic7700-eth-dwmac", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = eic7700_dwmac_match, + }, +}; +module_platform_driver(eic7700_dwmac_driver); + +MODULE_AUTHOR("Zhi Li <lizhi2@eswincomputing.com>"); +MODULE_AUTHOR("Shuang Liang <liangshuang@eswincomputing.com>"); +MODULE_AUTHOR("Shangjuan Wei <weishangjuan@eswincomputing.com>"); +MODULE_DESCRIPTION("Eswin eic7700 qos ethernet driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c index 5d279fa54b3e..db288fbd5a4d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-imx.c @@ -23,18 +23,13 @@ #include "stmmac_platform.h" #define GPR_ENET_QOS_INTF_MODE_MASK GENMASK(21, 16) -#define GPR_ENET_QOS_INTF_SEL_MII (0x0 << 16) -#define GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 16) -#define GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 16) +#define GPR_ENET_QOS_INTF_SEL_MASK GENMASK(20, 16) #define GPR_ENET_QOS_CLK_GEN_EN (0x1 << 19) #define GPR_ENET_QOS_CLK_TX_CLK_SEL (0x1 << 20) #define GPR_ENET_QOS_RGMII_EN (0x1 << 21) #define MX93_GPR_ENET_QOS_INTF_MODE_MASK GENMASK(3, 0) -#define MX93_GPR_ENET_QOS_INTF_MASK GENMASK(3, 1) -#define MX93_GPR_ENET_QOS_INTF_SEL_MII (0x0 << 1) -#define MX93_GPR_ENET_QOS_INTF_SEL_RMII (0x4 << 1) -#define MX93_GPR_ENET_QOS_INTF_SEL_RGMII (0x1 << 1) +#define MX93_GPR_ENET_QOS_INTF_SEL_MASK GENMASK(3, 1) #define MX93_GPR_ENET_QOS_CLK_GEN_EN (0x1 << 0) #define MX93_GPR_ENET_QOS_CLK_SEL_MASK BIT_MASK(0) #define MX93_GPR_CLK_SEL_OFFSET (4) @@ -44,13 +39,15 @@ #define RMII_RESET_SPEED (0x3 << 14) #define CTRL_SPEED_MASK GENMASK(15, 14) +struct imx_priv_data; + struct imx_dwmac_ops { u32 addr_width; u32 flags; bool mac_rgmii_txclk_auto_adj; - int (*fix_soc_reset)(void *priv, void __iomem *ioaddr); - int (*set_intf_mode)(struct plat_stmmacenet_data *plat_dat); + int (*fix_soc_reset)(struct stmmac_priv *priv, void __iomem *ioaddr); + int (*set_intf_mode)(struct imx_priv_data *dwmac, u8 phy_intf_sel); void (*fix_mac_speed)(void *priv, int speed, unsigned int mode); }; @@ -67,79 +64,46 @@ struct imx_priv_data { struct plat_stmmacenet_data *plat_dat; }; -static int imx8mp_set_intf_mode(struct plat_stmmacenet_data *plat_dat) +static int imx8mp_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel) { - struct imx_priv_data *dwmac = plat_dat->bsp_priv; - int val; - - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_MII: - val = GPR_ENET_QOS_INTF_SEL_MII; - break; - case PHY_INTERFACE_MODE_RMII: - val = GPR_ENET_QOS_INTF_SEL_RMII; - val |= (dwmac->rmii_refclk_ext ? 0 : GPR_ENET_QOS_CLK_TX_CLK_SEL); - break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - val = GPR_ENET_QOS_INTF_SEL_RGMII | - GPR_ENET_QOS_RGMII_EN; - break; - default: - pr_debug("imx dwmac doesn't support %d interface\n", - plat_dat->mac_interface); - return -EINVAL; - } + unsigned int val; + + val = FIELD_PREP(GPR_ENET_QOS_INTF_SEL_MASK, phy_intf_sel) | + GPR_ENET_QOS_CLK_GEN_EN; + + if (phy_intf_sel == PHY_INTF_SEL_RMII && !dwmac->rmii_refclk_ext) + val |= GPR_ENET_QOS_CLK_TX_CLK_SEL; + else if (phy_intf_sel == PHY_INTF_SEL_RGMII) + val |= GPR_ENET_QOS_RGMII_EN; - val |= GPR_ENET_QOS_CLK_GEN_EN; return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off, GPR_ENET_QOS_INTF_MODE_MASK, val); }; static int -imx8dxl_set_intf_mode(struct plat_stmmacenet_data *plat_dat) +imx8dxl_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel) { - int ret = 0; - /* TBD: depends on imx8dxl scu interfaces to be upstreamed */ - return ret; + return 0; } -static int imx93_set_intf_mode(struct plat_stmmacenet_data *plat_dat) +static int imx93_set_intf_mode(struct imx_priv_data *dwmac, u8 phy_intf_sel) { - struct imx_priv_data *dwmac = plat_dat->bsp_priv; - int val, ret; - - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_MII: - val = MX93_GPR_ENET_QOS_INTF_SEL_MII; - break; - case PHY_INTERFACE_MODE_RMII: - if (dwmac->rmii_refclk_ext) { - ret = regmap_clear_bits(dwmac->intf_regmap, - dwmac->intf_reg_off + - MX93_GPR_CLK_SEL_OFFSET, - MX93_GPR_ENET_QOS_CLK_SEL_MASK); - if (ret) - return ret; - } - val = MX93_GPR_ENET_QOS_INTF_SEL_RMII; - break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - val = MX93_GPR_ENET_QOS_INTF_SEL_RGMII; - break; - default: - dev_dbg(dwmac->dev, "imx dwmac doesn't support %d interface\n", - plat_dat->mac_interface); - return -EINVAL; + unsigned int val; + int ret; + + if (phy_intf_sel == PHY_INTF_SEL_RMII && dwmac->rmii_refclk_ext) { + ret = regmap_clear_bits(dwmac->intf_regmap, + dwmac->intf_reg_off + + MX93_GPR_CLK_SEL_OFFSET, + MX93_GPR_ENET_QOS_CLK_SEL_MASK); + if (ret) + return ret; } - val |= MX93_GPR_ENET_QOS_CLK_GEN_EN; + val = FIELD_PREP(MX93_GPR_ENET_QOS_INTF_SEL_MASK, phy_intf_sel) | + MX93_GPR_ENET_QOS_CLK_GEN_EN; + return regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off, MX93_GPR_ENET_QOS_INTF_MODE_MASK, val); }; @@ -170,34 +134,24 @@ static int imx_dwmac_clks_config(void *priv, bool enabled) return ret; } -static int imx_dwmac_init(struct platform_device *pdev, void *priv) +static int imx_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) { - struct plat_stmmacenet_data *plat_dat; - struct imx_priv_data *dwmac = priv; - int ret; - - plat_dat = dwmac->plat_dat; + struct imx_priv_data *dwmac = bsp_priv; - if (dwmac->ops->set_intf_mode) { - ret = dwmac->ops->set_intf_mode(plat_dat); - if (ret) - return ret; - } + if (!dwmac->ops->set_intf_mode) + return 0; - return 0; -} + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) + return -EINVAL; -static void imx_dwmac_exit(struct platform_device *pdev, void *priv) -{ - /* nothing to do now */ + return dwmac->ops->set_intf_mode(dwmac, phy_intf_sel); } static int imx_dwmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, phy_interface_t interface, int speed) { - struct imx_priv_data *dwmac = bsp_priv; - - interface = dwmac->plat_dat->mac_interface; if (interface == PHY_INTERFACE_MODE_RMII || interface == PHY_INTERFACE_MODE_MII) return 0; @@ -215,8 +169,8 @@ static void imx_dwmac_fix_speed(void *priv, int speed, unsigned int mode) plat_dat = dwmac->plat_dat; if (dwmac->ops->mac_rgmii_txclk_auto_adj || - (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) || - (plat_dat->mac_interface == PHY_INTERFACE_MODE_MII)) + (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII) || + (plat_dat->phy_interface == PHY_INTERFACE_MODE_MII)) return; rate = rgmii_clock(speed); @@ -244,8 +198,8 @@ static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode) if (regmap_read(dwmac->intf_regmap, dwmac->intf_reg_off, &iface)) return; - iface &= MX93_GPR_ENET_QOS_INTF_MASK; - if (iface != MX93_GPR_ENET_QOS_INTF_SEL_RGMII) + if (FIELD_GET(MX93_GPR_ENET_QOS_INTF_SEL_MASK, iface) != + PHY_INTF_SEL_RGMII) return; old_ctrl = readl(dwmac->base_addr + MAC_CTRL_REG); @@ -258,6 +212,7 @@ static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode) readl(dwmac->base_addr + MAC_CTRL_REG); usleep_range(10, 20); + iface &= MX93_GPR_ENET_QOS_INTF_SEL_MASK; iface |= MX93_GPR_ENET_QOS_CLK_GEN_EN; regmap_update_bits(dwmac->intf_regmap, dwmac->intf_reg_off, MX93_GPR_ENET_QOS_INTF_MODE_MASK, iface); @@ -265,16 +220,16 @@ static void imx93_dwmac_fix_speed(void *priv, int speed, unsigned int mode) writel(old_ctrl, dwmac->base_addr + MAC_CTRL_REG); } -static int imx_dwmac_mx93_reset(void *priv, void __iomem *ioaddr) +static int imx_dwmac_mx93_reset(struct stmmac_priv *priv, void __iomem *ioaddr) { - struct plat_stmmacenet_data *plat_dat = priv; + struct plat_stmmacenet_data *plat_dat = priv->plat; u32 value = readl(ioaddr + DMA_BUS_MODE); /* DMA SW reset */ value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); - if (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) { + if (plat_dat->phy_interface == PHY_INTERFACE_MODE_RMII) { usleep_range(100, 200); writel(RMII_RESET_SPEED, ioaddr + MAC_CTRL_REG); } @@ -301,6 +256,7 @@ imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev) dwmac->clk_mem = NULL; if (of_machine_is_compatible("fsl,imx8dxl") || + of_machine_is_compatible("fsl,imx91") || of_machine_is_compatible("fsl,imx93")) { dwmac->clk_mem = devm_clk_get(dev, "mem"); if (IS_ERR(dwmac->clk_mem)) { @@ -310,9 +266,10 @@ imx_dwmac_parse_dt(struct imx_priv_data *dwmac, struct device *dev) } if (of_machine_is_compatible("fsl,imx8mp") || + of_machine_is_compatible("fsl,imx91") || of_machine_is_compatible("fsl,imx93")) { /* Binding doc describes the propety: - * is required by i.MX8MP, i.MX93. + * is required by i.MX8MP, i.MX91, i.MX93. * is optinoal for i.MX8DXL. */ dwmac->intf_regmap = @@ -368,8 +325,7 @@ static int imx_dwmac_probe(struct platform_device *pdev) plat_dat->tx_queues_cfg[i].tbs_en = 1; plat_dat->host_dma_width = dwmac->ops->addr_width; - plat_dat->init = imx_dwmac_init; - plat_dat->exit = imx_dwmac_exit; + plat_dat->set_phy_intf_sel = imx_set_phy_intf_sel; plat_dat->clks_config = imx_dwmac_clks_config; plat_dat->bsp_priv = dwmac; dwmac->plat_dat = plat_dat; @@ -379,10 +335,6 @@ static int imx_dwmac_probe(struct platform_device *pdev) if (ret) return ret; - ret = imx_dwmac_init(pdev, dwmac); - if (ret) - goto err_dwmac_init; - if (dwmac->ops->fix_mac_speed) { plat_dat->fix_mac_speed = dwmac->ops->fix_mac_speed; } else if (!dwmac->ops->mac_rgmii_txclk_auto_adj) { @@ -392,16 +344,10 @@ static int imx_dwmac_probe(struct platform_device *pdev) dwmac->plat_dat->fix_soc_reset = dwmac->ops->fix_soc_reset; - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + ret = stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); if (ret) - goto err_drv_probe; - - return 0; + imx_dwmac_clks_config(dwmac, false); -err_drv_probe: - imx_dwmac_exit(pdev, plat_dat->bsp_priv); -err_dwmac_init: - imx_dwmac_clks_config(dwmac, false); return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c index 066783d66422..8e4a30c11db0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ingenic.c @@ -35,10 +35,6 @@ #define MACPHYC_RX_DELAY_MASK GENMASK(10, 4) #define MACPHYC_SOFT_RST_MASK GENMASK(3, 3) #define MACPHYC_PHY_INFT_MASK GENMASK(2, 0) -#define MACPHYC_PHY_INFT_RMII 0x4 -#define MACPHYC_PHY_INFT_RGMII 0x1 -#define MACPHYC_PHY_INFT_GMII 0x0 -#define MACPHYC_PHY_INFT_MII 0x0 #define MACPHYC_TX_DELAY_PS_MAX 2496 #define MACPHYC_TX_DELAY_PS_MIN 20 @@ -56,6 +52,7 @@ enum ingenic_mac_version { struct ingenic_mac { const struct ingenic_soc_info *soc_info; + struct plat_stmmacenet_data *plat_dat; struct device *dev; struct regmap *regmap; @@ -67,167 +64,93 @@ struct ingenic_soc_info { enum ingenic_mac_version version; u32 mask; - int (*set_mode)(struct plat_stmmacenet_data *plat_dat); -}; - -static int ingenic_mac_init(struct plat_stmmacenet_data *plat_dat) -{ - struct ingenic_mac *mac = plat_dat->bsp_priv; - int ret; - - if (mac->soc_info->set_mode) { - ret = mac->soc_info->set_mode(plat_dat); - if (ret) - return ret; - } + int (*set_mode)(struct ingenic_mac *mac, u8 phy_intf_sel); - return 0; -} + u8 valid_phy_intf_sel; +}; -static int jz4775_mac_set_mode(struct plat_stmmacenet_data *plat_dat) +static int jz4775_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel) { - struct ingenic_mac *mac = plat_dat->bsp_priv; unsigned int val; - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_MII: - val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) | - FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_MII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_MII\n"); - break; - - case PHY_INTERFACE_MODE_GMII: - val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) | - FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_GMII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_GMII\n"); - break; - - case PHY_INTERFACE_MODE_RMII: - val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) | - FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n"); - break; - - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: - val = FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT) | - FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n"); - break; - - default: - dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface); - return -EINVAL; - } + val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel) | + FIELD_PREP(MACPHYC_TXCLK_SEL_MASK, MACPHYC_TXCLK_SEL_INPUT); /* Update MAC PHY control register */ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val); } -static int x1000_mac_set_mode(struct plat_stmmacenet_data *plat_dat) +static int x1000_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel) { - struct ingenic_mac *mac = plat_dat->bsp_priv; - - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_RMII: - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n"); - break; - - default: - dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface); - return -EINVAL; - } - /* Update MAC PHY control register */ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, 0); } -static int x1600_mac_set_mode(struct plat_stmmacenet_data *plat_dat) +static int x1600_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel) { - struct ingenic_mac *mac = plat_dat->bsp_priv; unsigned int val; - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_RMII: - val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n"); - break; - - default: - dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface); - return -EINVAL; - } + val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel); /* Update MAC PHY control register */ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val); } -static int x1830_mac_set_mode(struct plat_stmmacenet_data *plat_dat) +static int x1830_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel) { - struct ingenic_mac *mac = plat_dat->bsp_priv; unsigned int val; - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_RMII: - val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) | - FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n"); - break; - - default: - dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface); - return -EINVAL; - } + val = FIELD_PREP(MACPHYC_MODE_SEL_MASK, MACPHYC_MODE_SEL_RMII) | + FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel); /* Update MAC PHY control register */ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val); } -static int x2000_mac_set_mode(struct plat_stmmacenet_data *plat_dat) +static int x2000_mac_set_mode(struct ingenic_mac *mac, u8 phy_intf_sel) { - struct ingenic_mac *mac = plat_dat->bsp_priv; unsigned int val; - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_RMII: - val = FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) | - FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN) | - FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RMII); - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RMII\n"); - break; - - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: - val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, MACPHYC_PHY_INFT_RGMII); + val = FIELD_PREP(MACPHYC_PHY_INFT_MASK, phy_intf_sel); + if (phy_intf_sel == PHY_INTF_SEL_RMII) { + val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN) | + FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN); + } else if (phy_intf_sel == PHY_INTF_SEL_RGMII) { if (mac->tx_delay == 0) val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_ORIGIN); else val |= FIELD_PREP(MACPHYC_TX_SEL_MASK, MACPHYC_TX_SEL_DELAY) | - FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1); + FIELD_PREP(MACPHYC_TX_DELAY_MASK, (mac->tx_delay + 9750) / 19500 - 1); if (mac->rx_delay == 0) val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_ORIGIN); else val |= FIELD_PREP(MACPHYC_RX_SEL_MASK, MACPHYC_RX_SEL_DELAY) | FIELD_PREP(MACPHYC_RX_DELAY_MASK, (mac->rx_delay + 9750) / 19500 - 1); - - dev_dbg(mac->dev, "MAC PHY Control Register: PHY_INTERFACE_MODE_RGMII\n"); - break; - - default: - dev_err(mac->dev, "Unsupported interface %d", plat_dat->mac_interface); - return -EINVAL; } /* Update MAC PHY control register */ return regmap_update_bits(mac->regmap, 0, mac->soc_info->mask, val); } +static int ingenic_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) +{ + struct ingenic_mac *mac = bsp_priv; + + if (!mac->soc_info->set_mode) + return 0; + + if (phy_intf_sel >= BITS_PER_BYTE || + ~mac->soc_info->valid_phy_intf_sel & BIT(phy_intf_sel)) + return -EINVAL; + + dev_dbg(mac->dev, "MAC PHY control register: interface %s\n", + phy_modes(mac->plat_dat->phy_interface)); + + return mac->soc_info->set_mode(mac, phy_intf_sel); +} + static int ingenic_mac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -284,49 +207,22 @@ static int ingenic_mac_probe(struct platform_device *pdev) mac->soc_info = data; mac->dev = &pdev->dev; + mac->plat_dat = plat_dat; plat_dat->bsp_priv = mac; + plat_dat->set_phy_intf_sel = ingenic_set_phy_intf_sel; - ret = ingenic_mac_init(plat_dat); - if (ret) - return ret; - - return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); -} - -#ifdef CONFIG_PM_SLEEP -static int ingenic_mac_suspend(struct device *dev) -{ - int ret; - - ret = stmmac_suspend(dev); - - return ret; + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } -static int ingenic_mac_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - int ret; - - ret = ingenic_mac_init(priv->plat); - if (ret) - return ret; - - ret = stmmac_resume(dev); - - return ret; -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(ingenic_mac_pm_ops, ingenic_mac_suspend, ingenic_mac_resume); - static struct ingenic_soc_info jz4775_soc_info = { .version = ID_JZ4775, .mask = MACPHYC_TXCLK_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK, .set_mode = jz4775_mac_set_mode, + .valid_phy_intf_sel = BIT(PHY_INTF_SEL_GMII_MII) | + BIT(PHY_INTF_SEL_RGMII) | + BIT(PHY_INTF_SEL_RMII), }; static struct ingenic_soc_info x1000_soc_info = { @@ -334,6 +230,7 @@ static struct ingenic_soc_info x1000_soc_info = { .mask = MACPHYC_SOFT_RST_MASK, .set_mode = x1000_mac_set_mode, + .valid_phy_intf_sel = BIT(PHY_INTF_SEL_RMII), }; static struct ingenic_soc_info x1600_soc_info = { @@ -341,6 +238,7 @@ static struct ingenic_soc_info x1600_soc_info = { .mask = MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK, .set_mode = x1600_mac_set_mode, + .valid_phy_intf_sel = BIT(PHY_INTF_SEL_RMII), }; static struct ingenic_soc_info x1830_soc_info = { @@ -348,6 +246,7 @@ static struct ingenic_soc_info x1830_soc_info = { .mask = MACPHYC_MODE_SEL_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK, .set_mode = x1830_mac_set_mode, + .valid_phy_intf_sel = BIT(PHY_INTF_SEL_RMII), }; static struct ingenic_soc_info x2000_soc_info = { @@ -356,6 +255,8 @@ static struct ingenic_soc_info x2000_soc_info = { MACPHYC_RX_DELAY_MASK | MACPHYC_SOFT_RST_MASK | MACPHYC_PHY_INFT_MASK, .set_mode = x2000_mac_set_mode, + .valid_phy_intf_sel = BIT(PHY_INTF_SEL_RGMII) | + BIT(PHY_INTF_SEL_RMII), }; static const struct of_device_id ingenic_mac_of_matches[] = { @@ -370,10 +271,9 @@ MODULE_DEVICE_TABLE(of, ingenic_mac_of_matches); static struct platform_driver ingenic_mac_driver = { .probe = ingenic_mac_probe, - .remove = stmmac_pltfr_remove, .driver = { .name = "ingenic-mac", - .pm = pm_ptr(&ingenic_mac_pm_ops), + .pm = &stmmac_pltfr_pm_ops, .of_match_table = ingenic_mac_of_matches, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c index 599def7b3a64..4ea7b0a803d7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel-plat.c @@ -113,16 +113,7 @@ static int intel_eth_plat_probe(struct platform_device *pdev) plat_dat->clk_tx_i = dwmac->tx_clk; plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; - plat_dat->bsp_priv = dwmac; - plat_dat->eee_usecs_rate = plat_dat->clk_ptp_rate; - - if (plat_dat->eee_usecs_rate > 0) { - u32 tx_lpi_usec; - - tx_lpi_usec = (plat_dat->eee_usecs_rate / 1000000) - 1; - writel(tx_lpi_usec, stmmac_res.addr + GMAC_1US_TIC_COUNTER); - } ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c index c8bb9265bbb4..aad1be1ec4c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c @@ -284,28 +284,28 @@ static void intel_serdes_powerdown(struct net_device *ndev, void *intel_data) } } -static void intel_speed_mode_2500(struct net_device *ndev, void *intel_data) +static void tgl_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, + unsigned long *interfaces) { - struct intel_priv_data *intel_priv = intel_data; - struct stmmac_priv *priv = netdev_priv(ndev); - int serdes_phy_addr = 0; - u32 data = 0; - - serdes_phy_addr = intel_priv->mdio_adhoc_addr; + struct intel_priv_data *intel_priv = bsp_priv; + phy_interface_t interface; + int data; /* Determine the link speed mode: 2.5Gbps/1Gbps */ - data = mdiobus_read(priv->mii, serdes_phy_addr, - SERDES_GCR); + data = mdiobus_read(priv->mii, intel_priv->mdio_adhoc_addr, SERDES_GCR); + if (data < 0) + return; - if (((data & SERDES_LINK_MODE_MASK) >> SERDES_LINK_MODE_SHIFT) == - SERDES_LINK_MODE_2G5) { + if (FIELD_GET(SERDES_LINK_MODE_MASK, data) == SERDES_LINK_MODE_2G5) { dev_info(priv->device, "Link Speed Mode: 2.5Gbps\n"); - priv->plat->max_speed = 2500; - priv->plat->phy_interface = PHY_INTERFACE_MODE_2500BASEX; priv->plat->mdio_bus_data->default_an_inband = false; + interface = PHY_INTERFACE_MODE_2500BASEX; } else { - priv->plat->max_speed = 1000; + interface = PHY_INTERFACE_MODE_SGMII; } + + __set_bit(interface, interfaces); + priv->plat->phy_interface = interface; } /* Program PTP Clock Frequency for different variant of @@ -371,9 +371,6 @@ static int intel_crosststamp(ktime_t *device, u32 acr_value; int i; - if (!boot_cpu_has(X86_FEATURE_ART)) - return -EOPNOTSUPP; - intel_priv = priv->plat->bsp_priv; /* Both internal crosstimestamping and external triggered event @@ -433,6 +430,12 @@ static int intel_crosststamp(ktime_t *device, return -ETIMEDOUT; } + *system = (struct system_counterval_t) { + .cycles = 0, + .cs_id = CSID_X86_ART, + .use_nsecs = false, + }; + num_snapshot = (readl(ioaddr + GMAC_TIMESTAMP_STATUS) & GMAC_TIMESTAMP_ATSNS_MASK) >> GMAC_TIMESTAMP_ATSNS_SHIFT; @@ -448,7 +451,7 @@ static int intel_crosststamp(ktime_t *device, } system->cycles *= intel_priv->crossts_adj; - system->cs_id = CSID_X86_ART; + priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN; return 0; @@ -560,31 +563,12 @@ static int intel_mac_finish(struct net_device *ndev, static void common_default_data(struct plat_stmmacenet_data *plat) { - plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ - plat->has_gmac = 1; + /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ + plat->clk_csr = STMMAC_CSR_20_35M; + plat->core_type = DWMAC_CORE_GMAC; plat->force_sf_dma_mode = 1; plat->mdio_bus_data->needs_reset = true; - - /* Set default value for multicast hash bins */ - plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - - /* Set the maxmtu to a default of JUMBO_LEN */ - plat->maxmtu = JUMBO_LEN; - - /* Set default number of RX and TX queues to use */ - plat->tx_queues_to_use = 1; - plat->rx_queues_to_use = 1; - - /* Disable Priority config by default */ - plat->tx_queues_cfg[0].use_prio = false; - plat->rx_queues_cfg[0].use_prio = false; - - /* Disable RX queues routing by default */ - plat->rx_queues_cfg[0].pkt_route = 0x0; } static struct phylink_pcs *intel_mgbe_select_pcs(struct stmmac_priv *priv, @@ -607,9 +591,8 @@ static int intel_mgbe_common_data(struct pci_dev *pdev, plat->pdev = pdev; plat->phy_addr = -1; - plat->clk_csr = 5; - plat->has_gmac = 0; - plat->has_gmac4 = 1; + plat->clk_csr = STMMAC_CSR_250_300M; + plat->core_type = DWMAC_CORE_GMAC4; plat->force_sf_dma_mode = 0; plat->flags |= (STMMAC_FLAG_TSO_EN | STMMAC_FLAG_SPH_DISABLE); @@ -626,22 +609,12 @@ static int intel_mgbe_common_data(struct pci_dev *pdev, plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP; - for (i = 0; i < plat->rx_queues_to_use; i++) { + for (i = 0; i < plat->rx_queues_to_use; i++) plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB; - plat->rx_queues_cfg[i].chan = i; - - /* Disable Priority config by default */ - plat->rx_queues_cfg[i].use_prio = false; - - /* Disable RX queues routing by default */ - plat->rx_queues_cfg[i].pkt_route = 0x0; - } for (i = 0; i < plat->tx_queues_to_use; i++) { plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB; - /* Disable Priority config by default */ - plat->tx_queues_cfg[i].use_prio = false; /* Default TX Q0 to use TSO and rest TXQ for TBS */ if (i > 0) plat->tx_queues_cfg[i].tbs_en = 1; @@ -677,12 +650,10 @@ static int intel_mgbe_common_data(struct pci_dev *pdev, plat->axi->axi_xit_frm = 0; plat->axi->axi_wr_osr_lmt = 1; plat->axi->axi_rd_osr_lmt = 1; - plat->axi->axi_blen[0] = 4; - plat->axi->axi_blen[1] = 8; - plat->axi->axi_blen[2] = 16; + plat->axi->axi_blen_regval = DMA_AXI_BLEN4 | DMA_AXI_BLEN8 | + DMA_AXI_BLEN16; plat->ptp_max_adj = plat->clk_ptp_rate; - plat->eee_usecs_rate = plat->clk_ptp_rate; /* Set system clock */ sprintf(clk_name, "%s-%s", "stmmac", pci_name(pdev)); @@ -704,15 +675,6 @@ static int intel_mgbe_common_data(struct pci_dev *pdev, plat->ptp_clk_freq_config = intel_mgbe_ptp_clk_freq_config; - /* Set default value for multicast hash bins */ - plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - - /* Set the maxmtu to a default of JUMBO_LEN */ - plat->maxmtu = JUMBO_LEN; - plat->flags |= STMMAC_FLAG_VLAN_FAIL_Q_EN; /* Use the last Rx queue */ @@ -750,7 +712,9 @@ static int intel_mgbe_common_data(struct pci_dev *pdev, plat->int_snapshot_num = AUX_SNAPSHOT1; - plat->crosststamp = intel_crosststamp; + if (boot_cpu_has(X86_FEATURE_ART)) + plat->crosststamp = intel_crosststamp; + plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN; /* Setup MSI vector offset specific to Intel mGbE controller */ @@ -933,7 +897,7 @@ static int tgl_common_data(struct pci_dev *pdev, plat->rx_queues_to_use = 6; plat->tx_queues_to_use = 4; plat->clk_ptp_rate = 204800000; - plat->speed_mode_2500 = intel_speed_mode_2500; + plat->get_interfaces = tgl_get_interfaces; plat->safety_feat_cfg->tsoee = 1; plat->safety_feat_cfg->mrxpee = 0; @@ -952,7 +916,6 @@ static int tgl_sgmii_phy0_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { plat->bus_id = 1; - plat->phy_interface = PHY_INTERFACE_MODE_SGMII; plat->serdes_powerup = intel_serdes_powerup; plat->serdes_powerdown = intel_serdes_powerdown; return tgl_common_data(pdev, plat); @@ -966,7 +929,6 @@ static int tgl_sgmii_phy1_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { plat->bus_id = 2; - plat->phy_interface = PHY_INTERFACE_MODE_SGMII; plat->serdes_powerup = intel_serdes_powerup; plat->serdes_powerdown = intel_serdes_powerdown; return tgl_common_data(pdev, plat); @@ -980,7 +942,6 @@ static int adls_sgmii_phy0_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { plat->bus_id = 1; - plat->phy_interface = PHY_INTERFACE_MODE_SGMII; /* SerDes power up and power down are done in BIOS for ADL */ @@ -995,7 +956,6 @@ static int adls_sgmii_phy1_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { plat->bus_id = 2; - plat->phy_interface = PHY_INTERFACE_MODE_SGMII; /* SerDes power up and power down are done in BIOS for ADL */ @@ -1230,6 +1190,37 @@ static int stmmac_config_multi_msi(struct pci_dev *pdev, return 0; } +static int intel_eth_pci_suspend(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_wake_from_d3(pdev, true); + pci_set_power_state(pdev, PCI_D3hot); + return 0; +} + +static int intel_eth_pci_resume(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return 0; +} + /** * intel_eth_pci_probe * @@ -1255,7 +1246,7 @@ static int intel_eth_pci_probe(struct pci_dev *pdev, if (!intel_priv) return -ENOMEM; - plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + plat = stmmac_plat_dat_alloc(&pdev->dev); if (!plat) return -ENOMEM; @@ -1291,6 +1282,9 @@ static int intel_eth_pci_probe(struct pci_dev *pdev, pci_set_master(pdev); plat->bsp_priv = intel_priv; + plat->suspend = intel_eth_pci_suspend; + plat->resume = intel_eth_pci_resume; + intel_priv->mdio_adhoc_addr = INTEL_MGBE_ADHOC_ADDR; intel_priv->crossts_adj = 1; @@ -1313,13 +1307,6 @@ static int intel_eth_pci_probe(struct pci_dev *pdev, memset(&res, 0, sizeof(res)); res.addr = pcim_iomap_table(pdev)[0]; - if (plat->eee_usecs_rate > 0) { - u32 tx_lpi_usec; - - tx_lpi_usec = (plat->eee_usecs_rate / 1000000) - 1; - writel(tx_lpi_usec, res.addr + GMAC_1US_TIC_COUNTER); - } - ret = stmmac_config_multi_msi(pdev, plat, &res); if (ret) { ret = stmmac_config_single_msi(pdev, plat, &res); @@ -1361,44 +1348,6 @@ static void intel_eth_pci_remove(struct pci_dev *pdev) clk_unregister_fixed_rate(priv->plat->stmmac_clk); } -static int __maybe_unused intel_eth_pci_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - - pci_wake_from_d3(pdev, true); - pci_set_power_state(pdev, PCI_D3hot); - return 0; -} - -static int __maybe_unused intel_eth_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - ret = pcim_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - return stmmac_resume(dev); -} - -static SIMPLE_DEV_PM_OPS(intel_eth_pm_ops, intel_eth_pci_suspend, - intel_eth_pci_resume); - #define PCI_DEVICE_ID_INTEL_QUARK 0x0937 #define PCI_DEVICE_ID_INTEL_EHL_RGMII1G 0x4b30 #define PCI_DEVICE_ID_INTEL_EHL_SGMII1G 0x4b31 @@ -1448,7 +1397,7 @@ static struct pci_driver intel_eth_pci_driver = { .probe = intel_eth_pci_probe, .remove = intel_eth_pci_remove, .driver = { - .pm = &intel_eth_pm_ops, + .pm = &stmmac_simple_pm_ops, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h index a12f8e65f89f..7511c224b312 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.h @@ -21,7 +21,6 @@ #define SERDES_RATE_MASK GENMASK(9, 8) #define SERDES_PCLK_MASK GENMASK(14, 12) /* PCLK rate to PHY */ #define SERDES_LINK_MODE_MASK GENMASK(2, 1) -#define SERDES_LINK_MODE_SHIFT 1 #define SERDES_PWR_ST_SHIFT 4 #define SERDES_PWR_ST_P0 0x0 #define SERDES_PWR_ST_P3 0x3 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c index ca4035cbb55b..c05f85534f0c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -473,7 +473,7 @@ static int ipq806x_gmac_probe(struct platform_device *pdev) return err; } - plat_dat->has_gmac = true; + plat_dat->core_type = DWMAC_CORE_GMAC; plat_dat->bsp_priv = gmac; plat_dat->set_clk_tx_rate = ipq806x_gmac_set_clk_tx_rate; plat_dat->multicast_filter_bins = 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c index 1a93787056a7..107a7c84ace8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c @@ -8,6 +8,7 @@ #include <linux/device.h> #include <linux/of_irq.h> #include "stmmac.h" +#include "stmmac_libpci.h" #include "dwmac_dma.h" #include "dwmac1000.h" @@ -66,12 +67,14 @@ DMA_STATUS_TPS | DMA_STATUS_TI | \ DMA_STATUS_MSK_COMMON_LOONGSON) -#define PCI_DEVICE_ID_LOONGSON_GMAC 0x7a03 +#define PCI_DEVICE_ID_LOONGSON_GMAC1 0x7a03 +#define PCI_DEVICE_ID_LOONGSON_GMAC2 0x7a23 #define PCI_DEVICE_ID_LOONGSON_GNET 0x7a13 -#define DWMAC_CORE_LS_MULTICHAN 0x10 /* Loongson custom ID */ -#define CHANNEL_NUM 8 +#define DWMAC_CORE_MULTICHAN_V1 0x10 /* Loongson custom ID 0x10 */ +#define DWMAC_CORE_MULTICHAN_V2 0x12 /* Loongson custom ID 0x12 */ struct loongson_data { + u32 multichan; u32 loongson_id; struct device *dev; }; @@ -83,64 +86,53 @@ struct stmmac_pci_info { static void loongson_default_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { + struct loongson_data *ld = plat->bsp_priv; + /* Get bus_id, this can be overwritten later */ plat->bus_id = pci_dev_id(pdev); - plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ - plat->has_gmac = 1; + /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ + plat->clk_csr = STMMAC_CSR_20_35M; + plat->core_type = DWMAC_CORE_GMAC; plat->force_sf_dma_mode = 1; - /* Set default value for multicast hash bins */ + /* Increase the default value for multicast hash bins */ plat->multicast_filter_bins = 256; - plat->mac_interface = PHY_INTERFACE_MODE_NA; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - - /* Set the maxmtu to a default of JUMBO_LEN */ - plat->maxmtu = JUMBO_LEN; - - /* Disable Priority config by default */ - plat->tx_queues_cfg[0].use_prio = false; - plat->rx_queues_cfg[0].use_prio = false; - - /* Disable RX queues routing by default */ - plat->rx_queues_cfg[0].pkt_route = 0x0; - plat->clk_ref_rate = 125000000; plat->clk_ptp_rate = 125000000; - /* Default to phy auto-detection */ - plat->phy_addr = -1; - plat->dma_cfg->pbl = 32; plat->dma_cfg->pblx8 = true; -} -static int loongson_gmac_data(struct pci_dev *pdev, - struct plat_stmmacenet_data *plat) -{ - struct loongson_data *ld; - int i; - - ld = plat->bsp_priv; - - loongson_default_data(pdev, plat); - - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) { - plat->rx_queues_to_use = CHANNEL_NUM; - plat->tx_queues_to_use = CHANNEL_NUM; + switch (ld->loongson_id) { + case DWMAC_CORE_MULTICHAN_V1: + ld->multichan = 1; + plat->rx_queues_to_use = 8; + plat->tx_queues_to_use = 8; /* Only channel 0 supports checksum, * so turn off checksum to enable multiple channels. */ - for (i = 1; i < CHANNEL_NUM; i++) + for (int i = 1; i < 8; i++) plat->tx_queues_cfg[i].coe_unsupported = 1; - } else { - plat->tx_queues_to_use = 1; - plat->rx_queues_to_use = 1; + + break; + case DWMAC_CORE_MULTICHAN_V2: + ld->multichan = 1; + plat->rx_queues_to_use = 4; + plat->tx_queues_to_use = 4; + break; + default: + ld->multichan = 0; + break; } +} + +static int loongson_gmac_data(struct pci_dev *pdev, + struct plat_stmmacenet_data *plat) +{ + loongson_default_data(pdev, plat); plat->phy_interface = PHY_INTERFACE_MODE_RGMII_ID; @@ -172,27 +164,8 @@ static void loongson_gnet_fix_speed(void *priv, int speed, unsigned int mode) static int loongson_gnet_data(struct pci_dev *pdev, struct plat_stmmacenet_data *plat) { - struct loongson_data *ld; - int i; - - ld = plat->bsp_priv; - loongson_default_data(pdev, plat); - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) { - plat->rx_queues_to_use = CHANNEL_NUM; - plat->tx_queues_to_use = CHANNEL_NUM; - - /* Only channel 0 supports checksum, - * so turn off checksum to enable multiple channels. - */ - for (i = 1; i < CHANNEL_NUM; i++) - plat->tx_queues_cfg[i].coe_unsupported = 1; - } else { - plat->tx_queues_to_use = 1; - plat->rx_queues_to_use = 1; - } - plat->phy_interface = PHY_INTERFACE_MODE_GMII; plat->mdio_bus_data->phy_mask = ~(u32)BIT(2); plat->fix_mac_speed = loongson_gnet_fix_speed; @@ -330,10 +303,9 @@ static int loongson_dwmac_dma_interrupt(struct stmmac_priv *priv, return ret; } -static struct mac_device_info *loongson_dwmac_setup(void *apriv) +static int loongson_dwmac_setup(void *apriv, struct mac_device_info *mac) { struct stmmac_priv *priv = apriv; - struct mac_device_info *mac; struct stmmac_dma_ops *dma; struct loongson_data *ld; struct pci_dev *pdev; @@ -341,23 +313,19 @@ static struct mac_device_info *loongson_dwmac_setup(void *apriv) ld = priv->plat->bsp_priv; pdev = to_pci_dev(priv->device); - mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); - if (!mac) - return NULL; - dma = devm_kzalloc(priv->device, sizeof(*dma), GFP_KERNEL); if (!dma) - return NULL; + return -ENOMEM; /* The Loongson GMAC and GNET devices are based on the DW GMAC - * v3.50a and v3.73a IP-cores. But the HW designers have changed the - * GMAC_VERSION.SNPSVER field to the custom 0x10 value on the - * network controllers with the multi-channels feature + * v3.50a and v3.73a IP-cores. But the HW designers have changed + * the GMAC_VERSION.SNPSVER field to the custom 0x10/0x12 value + * on the network controllers with the multi-channels feature * available to emphasize the differences: multiple DMA-channels, * AV feature and GMAC_INT_STATUS CSR flags layout. Get back the * original value so the correct HW-interface would be selected. */ - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) { + if (ld->multichan) { priv->synopsys_id = DWMAC_CORE_3_70; *dma = dwmac1000_dma_ops; dma->init_chan = loongson_dwmac_dma_init_channel; @@ -378,13 +346,13 @@ static struct mac_device_info *loongson_dwmac_setup(void *apriv) if (mac->multicast_filter_bins) mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); - /* Loongson GMAC doesn't support the flow control. LS2K2000 - * GNET doesn't support the half-duplex link mode. + /* Loongson GMAC doesn't support the flow control. Loongson GNET + * without multi-channel doesn't support the half-duplex link mode. */ - if (pdev->device == PCI_DEVICE_ID_LOONGSON_GMAC) { + if (pdev->device != PCI_DEVICE_ID_LOONGSON_GNET) { mac->link.caps = MAC_10 | MAC_100 | MAC_1000; } else { - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) + if (ld->multichan) mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000; else @@ -406,16 +374,18 @@ static struct mac_device_info *loongson_dwmac_setup(void *apriv) mac->mii.clk_csr_shift = 2; mac->mii.clk_csr_mask = GENMASK(5, 2); - return mac; + return 0; } static int loongson_dwmac_msi_config(struct pci_dev *pdev, struct plat_stmmacenet_data *plat, struct stmmac_resources *res) { - int i, ret, vecs; + int i, ch_num, ret, vecs; + + ch_num = min(plat->tx_queues_to_use, plat->rx_queues_to_use); - vecs = roundup_pow_of_two(CHANNEL_NUM * 2 + 1); + vecs = roundup_pow_of_two(ch_num * 2 + 1); ret = pci_alloc_irq_vectors(pdev, vecs, vecs, PCI_IRQ_MSI); if (ret < 0) { dev_warn(&pdev->dev, "Failed to allocate MSI IRQs\n"); @@ -424,14 +394,12 @@ static int loongson_dwmac_msi_config(struct pci_dev *pdev, res->irq = pci_irq_vector(pdev, 0); - for (i = 0; i < plat->rx_queues_to_use; i++) { - res->rx_irq[CHANNEL_NUM - 1 - i] = - pci_irq_vector(pdev, 1 + i * 2); + for (i = 0; i < ch_num; i++) { + res->rx_irq[ch_num - 1 - i] = pci_irq_vector(pdev, 1 + i * 2); } - for (i = 0; i < plat->tx_queues_to_use; i++) { - res->tx_irq[CHANNEL_NUM - 1 - i] = - pci_irq_vector(pdev, 2 + i * 2); + for (i = 0; i < ch_num; i++) { + res->tx_irq[ch_num - 1 - i] = pci_irq_vector(pdev, 2 + i * 2); } plat->flags |= STMMAC_FLAG_MULTI_MSI_EN; @@ -518,10 +486,15 @@ static int loongson_dwmac_acpi_config(struct pci_dev *pdev, } /* Loongson's DWMAC device may take nearly two seconds to complete DMA reset */ -static int loongson_dwmac_fix_reset(void *priv, void __iomem *ioaddr) +static int loongson_dwmac_fix_reset(struct stmmac_priv *priv, void __iomem *ioaddr) { u32 value = readl(ioaddr + DMA_BUS_MODE); + if (value & DMA_BUS_MODE_SFT_RESET) { + netdev_err(priv->dev, "the PHY clock is missing\n"); + return -EINVAL; + } + value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); @@ -538,7 +511,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id struct loongson_data *ld; int ret; - plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + plat = stmmac_plat_dat_alloc(&pdev->dev); if (!plat) return -ENOMEM; @@ -572,8 +545,10 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id goto err_disable_device; plat->bsp_priv = ld; - plat->setup = loongson_dwmac_setup; + plat->mac_setup = loongson_dwmac_setup; plat->fix_soc_reset = loongson_dwmac_fix_reset; + plat->suspend = stmmac_pci_plat_suspend; + plat->resume = stmmac_pci_plat_resume; ld->dev = &pdev->dev; ld->loongson_id = readl(res.addr + GMAC_VERSION) & 0xff; @@ -593,7 +568,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id goto err_disable_device; /* Use the common MAC IRQ if per-channel MSIs allocation failed */ - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) + if (ld->multichan) loongson_dwmac_msi_config(pdev, plat, &res); ret = stmmac_dvr_probe(&pdev->dev, plat, &res); @@ -605,7 +580,7 @@ static int loongson_dwmac_probe(struct pci_dev *pdev, const struct pci_device_id err_plat_clear: if (dev_of_node(&pdev->dev)) loongson_dwmac_dt_clear(pdev, plat); - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) + if (ld->multichan) loongson_dwmac_msi_clear(pdev); err_disable_device: pci_disable_device(pdev); @@ -624,52 +599,15 @@ static void loongson_dwmac_remove(struct pci_dev *pdev) if (dev_of_node(&pdev->dev)) loongson_dwmac_dt_clear(pdev, priv->plat); - if (ld->loongson_id == DWMAC_CORE_LS_MULTICHAN) + if (ld->multichan) loongson_dwmac_msi_clear(pdev); pci_disable_device(pdev); } -static int __maybe_unused loongson_dwmac_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - - pci_disable_device(pdev); - pci_wake_from_d3(pdev, true); - return 0; -} - -static int __maybe_unused loongson_dwmac_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - return stmmac_resume(dev); -} - -static SIMPLE_DEV_PM_OPS(loongson_dwmac_pm_ops, loongson_dwmac_suspend, - loongson_dwmac_resume); - static const struct pci_device_id loongson_dwmac_id_table[] = { - { PCI_DEVICE_DATA(LOONGSON, GMAC, &loongson_gmac_pci_info) }, + { PCI_DEVICE_DATA(LOONGSON, GMAC1, &loongson_gmac_pci_info) }, + { PCI_DEVICE_DATA(LOONGSON, GMAC2, &loongson_gmac_pci_info) }, { PCI_DEVICE_DATA(LOONGSON, GNET, &loongson_gnet_pci_info) }, {} }; @@ -681,7 +619,7 @@ static struct pci_driver loongson_dwmac_driver = { .probe = loongson_dwmac_probe, .remove = loongson_dwmac_remove, .driver = { - .pm = &loongson_dwmac_pm_ops, + .pm = &stmmac_simple_pm_ops, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c index 3e86810717d3..de9aba756aac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson1.c @@ -38,30 +38,54 @@ #define GMAC_SHUT BIT(6) #define PHY_INTF_SELI GENMASK(30, 28) -#define PHY_INTF_MII FIELD_PREP(PHY_INTF_SELI, 0) -#define PHY_INTF_RMII FIELD_PREP(PHY_INTF_SELI, 4) struct ls1x_dwmac { struct plat_stmmacenet_data *plat_dat; struct regmap *regmap; + unsigned int id; }; -static int ls1b_dwmac_syscon_init(struct platform_device *pdev, void *priv) +struct ls1x_data { + int (*setup)(struct platform_device *pdev, + struct plat_stmmacenet_data *plat_dat); + int (*init)(struct device *dev, void *bsp_priv); +}; + +static int ls1b_dwmac_setup(struct platform_device *pdev, + struct plat_stmmacenet_data *plat_dat) { - struct ls1x_dwmac *dwmac = priv; - struct plat_stmmacenet_data *plat = dwmac->plat_dat; - struct regmap *regmap = dwmac->regmap; + struct ls1x_dwmac *dwmac = plat_dat->bsp_priv; struct resource *res; - unsigned long reg_base; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { + /* This shouldn't fail - stmmac_get_platform_resources() + * already mapped this resource. + */ dev_err(&pdev->dev, "Could not get IO_MEM resources\n"); return -EINVAL; } - reg_base = (unsigned long)res->start; - if (reg_base == LS1B_GMAC0_BASE) { + if (res->start == LS1B_GMAC0_BASE) { + dwmac->id = 0; + } else if (res->start == LS1B_GMAC1_BASE) { + dwmac->id = 1; + } else { + dev_err(&pdev->dev, "Invalid Ethernet MAC base address %pR", + res); + return -EINVAL; + } + + return 0; +} + +static int ls1b_dwmac_syscon_init(struct device *dev, void *priv) +{ + struct ls1x_dwmac *dwmac = priv; + struct plat_stmmacenet_data *plat = dwmac->plat_dat; + struct regmap *regmap = dwmac->regmap; + + if (dwmac->id == 0) { switch (plat->phy_interface) { case PHY_INTERFACE_MODE_RGMII_ID: regmap_update_bits(regmap, LS1X_SYSCON0, @@ -74,13 +98,13 @@ static int ls1b_dwmac_syscon_init(struct platform_device *pdev, void *priv) GMAC0_USE_TXCLK | GMAC0_USE_PWM01); break; default: - dev_err(&pdev->dev, "Unsupported PHY mode %u\n", + dev_err(dev, "Unsupported PHY mode %u\n", plat->phy_interface); return -EOPNOTSUPP; } regmap_update_bits(regmap, LS1X_SYSCON0, GMAC0_SHUT, 0); - } else if (reg_base == LS1B_GMAC1_BASE) { + } else if (dwmac->id == 1) { regmap_update_bits(regmap, LS1X_SYSCON0, GMAC1_USE_UART1 | GMAC1_USE_UART0, GMAC1_USE_UART1 | GMAC1_USE_UART0); @@ -98,42 +122,34 @@ static int ls1b_dwmac_syscon_init(struct platform_device *pdev, void *priv) GMAC1_USE_TXCLK | GMAC1_USE_PWM23); break; default: - dev_err(&pdev->dev, "Unsupported PHY mode %u\n", + dev_err(dev, "Unsupported PHY mode %u\n", plat->phy_interface); return -EOPNOTSUPP; } regmap_update_bits(regmap, LS1X_SYSCON1, GMAC1_SHUT, 0); - } else { - dev_err(&pdev->dev, "Invalid Ethernet MAC base address %lx", - reg_base); - return -EINVAL; } return 0; } -static int ls1c_dwmac_syscon_init(struct platform_device *pdev, void *priv) +static int ls1c_dwmac_syscon_init(struct device *dev, void *priv) { struct ls1x_dwmac *dwmac = priv; struct plat_stmmacenet_data *plat = dwmac->plat_dat; struct regmap *regmap = dwmac->regmap; + int phy_intf_sel; - switch (plat->phy_interface) { - case PHY_INTERFACE_MODE_MII: - regmap_update_bits(regmap, LS1X_SYSCON1, PHY_INTF_SELI, - PHY_INTF_MII); - break; - case PHY_INTERFACE_MODE_RMII: - regmap_update_bits(regmap, LS1X_SYSCON1, PHY_INTF_SELI, - PHY_INTF_RMII); - break; - default: - dev_err(&pdev->dev, "Unsupported PHY-mode %u\n", + phy_intf_sel = stmmac_get_phy_intf_sel(plat->phy_interface); + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RMII) { + dev_err(dev, "Unsupported PHY-mode %u\n", plat->phy_interface); return -EOPNOTSUPP; } + regmap_update_bits(regmap, LS1X_SYSCON1, PHY_INTF_SELI, + FIELD_PREP(PHY_INTF_SELI, phy_intf_sel)); regmap_update_bits(regmap, LS1X_SYSCON0, GMAC0_SHUT, 0); return 0; @@ -143,9 +159,9 @@ static int ls1x_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; + const struct ls1x_data *data; struct regmap *regmap; struct ls1x_dwmac *dwmac; - int (*init)(struct platform_device *pdev, void *priv); int ret; ret = stmmac_get_platform_resources(pdev, &stmmac_res); @@ -159,8 +175,8 @@ static int ls1x_dwmac_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(regmap), "Unable to find syscon\n"); - init = of_device_get_match_data(&pdev->dev); - if (!init) { + data = of_device_get_match_data(&pdev->dev); + if (!data) { dev_err(&pdev->dev, "No of match data provided\n"); return -EINVAL; } @@ -175,21 +191,36 @@ static int ls1x_dwmac_probe(struct platform_device *pdev) "dt configuration failed\n"); plat_dat->bsp_priv = dwmac; - plat_dat->init = init; + plat_dat->init = data->init; dwmac->plat_dat = plat_dat; dwmac->regmap = regmap; + if (data->setup) { + ret = data->setup(pdev, plat_dat); + if (ret) + return ret; + } + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } +static const struct ls1x_data ls1b_dwmac_data = { + .setup = ls1b_dwmac_setup, + .init = ls1b_dwmac_syscon_init, +}; + +static const struct ls1x_data ls1c_dwmac_data = { + .init = ls1c_dwmac_syscon_init, +}; + static const struct of_device_id ls1x_dwmac_match[] = { { .compatible = "loongson,ls1b-gmac", - .data = &ls1b_dwmac_syscon_init, + .data = &ls1b_dwmac_data, }, { .compatible = "loongson,ls1c-emac", - .data = &ls1c_dwmac_syscon_init, + .data = &ls1c_dwmac_data, }, { } }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c index 22653ffd2a04..c68d7de1f8ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c @@ -21,16 +21,29 @@ /* Register defines for CREG syscon */ #define LPC18XX_CREG_CREG6 0x12c -# define LPC18XX_CREG_CREG6_ETHMODE_MASK 0x7 -# define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0 -# define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4 +# define LPC18XX_CREG_CREG6_ETHMODE_MASK GENMASK(2, 0) + +static int lpc18xx_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) +{ + struct regmap *reg = bsp_priv; + + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RMII) + return -EINVAL; + + regmap_update_bits(reg, LPC18XX_CREG_CREG6, + LPC18XX_CREG_CREG6_ETHMODE_MASK, + FIELD_PREP(LPC18XX_CREG_CREG6_ETHMODE_MASK, + phy_intf_sel)); + + return 0; +} static int lpc18xx_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; - struct regmap *reg; - u8 ethmode; + struct regmap *regmap; int ret; ret = stmmac_get_platform_resources(pdev, &stmmac_res); @@ -41,25 +54,16 @@ static int lpc18xx_dwmac_probe(struct platform_device *pdev) if (IS_ERR(plat_dat)) return PTR_ERR(plat_dat); - plat_dat->has_gmac = true; + plat_dat->core_type = DWMAC_CORE_GMAC; - reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); - if (IS_ERR(reg)) { + regmap = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); + if (IS_ERR(regmap)) { dev_err(&pdev->dev, "syscon lookup failed\n"); - return PTR_ERR(reg); - } - - if (plat_dat->mac_interface == PHY_INTERFACE_MODE_MII) { - ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII; - } else if (plat_dat->mac_interface == PHY_INTERFACE_MODE_RMII) { - ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; - } else { - dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); - return -EINVAL; + return PTR_ERR(regmap); } - regmap_update_bits(reg, LPC18XX_CREG_CREG6, - LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); + plat_dat->bsp_priv = regmap; + plat_dat->set_phy_intf_sel = lpc18xx_set_phy_intf_sel; return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c index d178d5ddc7c7..1f2d7d19ca56 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c @@ -17,9 +17,6 @@ /* Peri Configuration register for mt2712 */ #define PERI_ETH_PHY_INTF_SEL 0x418 -#define PHY_INTF_MII 0 -#define PHY_INTF_RGMII 1 -#define PHY_INTF_RMII 4 #define RMII_CLK_SRC_RXC BIT(4) #define RMII_CLK_SRC_INTERNAL BIT(5) @@ -88,7 +85,8 @@ struct mediatek_dwmac_plat_data { }; struct mediatek_dwmac_variant { - int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat); + int (*dwmac_set_phy_interface)(struct mediatek_dwmac_plat_data *plat, + u8 phy_intf_sel); int (*dwmac_set_delay)(struct mediatek_dwmac_plat_data *plat); /* clock ids to be requested */ @@ -109,29 +107,16 @@ static const char * const mt8195_dwmac_clk_l[] = { "axi", "apb", "mac_cg", "mac_main", "ptp_ref" }; -static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat) +static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat, + u8 phy_intf_sel) { - int rmii_clk_from_mac = plat->rmii_clk_from_mac ? RMII_CLK_SRC_INTERNAL : 0; - int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0; - u32 intf_val = 0; + u32 intf_val = phy_intf_sel; - /* select phy interface in top control domain */ - switch (plat->phy_mode) { - case PHY_INTERFACE_MODE_MII: - intf_val |= PHY_INTF_MII; - break; - case PHY_INTERFACE_MODE_RMII: - intf_val |= (PHY_INTF_RMII | rmii_rxc | rmii_clk_from_mac); - break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_ID: - intf_val |= PHY_INTF_RGMII; - break; - default: - dev_err(plat->dev, "phy interface not supported\n"); - return -EINVAL; + if (phy_intf_sel == PHY_INTF_SEL_RMII) { + if (plat->rmii_clk_from_mac) + intf_val |= RMII_CLK_SRC_INTERNAL; + if (plat->rmii_rxc) + intf_val |= RMII_CLK_SRC_RXC; } regmap_write(plat->peri_regmap, PERI_ETH_PHY_INTF_SEL, intf_val); @@ -288,30 +273,16 @@ static const struct mediatek_dwmac_variant mt2712_gmac_variant = { .tx_delay_max = 17600, }; -static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat) +static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat, + u8 phy_intf_sel) { - int rmii_clk_from_mac = plat->rmii_clk_from_mac ? MT8195_RMII_CLK_SRC_INTERNAL : 0; - int rmii_rxc = plat->rmii_rxc ? MT8195_RMII_CLK_SRC_RXC : 0; - u32 intf_val = 0; + u32 intf_val = FIELD_PREP(MT8195_ETH_INTF_SEL, phy_intf_sel); - /* select phy interface in top control domain */ - switch (plat->phy_mode) { - case PHY_INTERFACE_MODE_MII: - intf_val |= FIELD_PREP(MT8195_ETH_INTF_SEL, PHY_INTF_MII); - break; - case PHY_INTERFACE_MODE_RMII: - intf_val |= (rmii_rxc | rmii_clk_from_mac); - intf_val |= FIELD_PREP(MT8195_ETH_INTF_SEL, PHY_INTF_RMII); - break; - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_TXID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_ID: - intf_val |= FIELD_PREP(MT8195_ETH_INTF_SEL, PHY_INTF_RGMII); - break; - default: - dev_err(plat->dev, "phy interface not supported\n"); - return -EINVAL; + if (phy_intf_sel == PHY_INTF_SEL_RMII) { + if (plat->rmii_clk_from_mac) + intf_val |= MT8195_RMII_CLK_SRC_INTERNAL; + if (plat->rmii_rxc) + intf_val |= MT8195_RMII_CLK_SRC_RXC; } /* MT8195 only support external PHY */ @@ -523,16 +494,24 @@ static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat) return ret; } -static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) +static int mediatek_dwmac_init(struct device *dev, void *priv) { struct mediatek_dwmac_plat_data *plat = priv; const struct mediatek_dwmac_variant *variant = plat->variant; - int ret; + int phy_intf_sel, ret; if (variant->dwmac_set_phy_interface) { - ret = variant->dwmac_set_phy_interface(plat); + phy_intf_sel = stmmac_get_phy_intf_sel(plat->phy_mode); + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) { + dev_err(plat->dev, "phy interface not supported\n"); + return phy_intf_sel < 0 ? phy_intf_sel : -EINVAL; + } + + ret = variant->dwmac_set_phy_interface(plat, phy_intf_sel); if (ret) { - dev_err(plat->dev, "failed to set phy interface, err = %d\n", ret); + dev_err(dev, "failed to set phy interface, err = %d\n", ret); return ret; } } @@ -540,7 +519,7 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv) if (variant->dwmac_set_delay) { ret = variant->dwmac_set_delay(plat); if (ret) { - dev_err(plat->dev, "failed to set delay value, err = %d\n", ret); + dev_err(dev, "failed to set delay value, err = %d\n", ret); return ret; } } @@ -581,7 +560,6 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev, int i; priv_plat->phy_mode = plat->phy_interface; - plat->mac_interface = priv_plat->phy_mode; if (priv_plat->mac_wol) plat->flags &= ~STMMAC_FLAG_USE_PHY_WOL; else @@ -590,7 +568,7 @@ static int mediatek_dwmac_common_data(struct platform_device *pdev, plat->maxmtu = ETH_DATA_LEN; plat->host_dma_width = priv_plat->variant->dma_bit_mask; plat->bsp_priv = priv_plat; - plat->init = mediatek_dwmac_init; + plat->resume = mediatek_dwmac_init; plat->clks_config = mediatek_dwmac_clks_config; plat->safety_feat_cfg = devm_kzalloc(&pdev->dev, @@ -655,7 +633,7 @@ static int mediatek_dwmac_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); mediatek_dwmac_common_data(pdev, plat_dat, priv_plat); - mediatek_dwmac_init(pdev, priv_plat); + mediatek_dwmac_init(&pdev->dev, priv_plat); ret = mediatek_dwmac_clks_config(priv_plat, true); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c index a50782994b97..e4d5c41294f4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c @@ -26,8 +26,6 @@ #define PRG_ETH0_RGMII_MODE BIT(0) #define PRG_ETH0_EXT_PHY_MODE_MASK GENMASK(2, 0) -#define PRG_ETH0_EXT_RGMII_MODE 1 -#define PRG_ETH0_EXT_RMII_MODE 4 /* mux to choose between fclk_div2 (bit unset) and mpll2 (bit set) */ #define PRG_ETH0_CLK_M250_SEL_MASK GENMASK(4, 4) @@ -238,28 +236,20 @@ static int meson8b_set_phy_mode(struct meson8b_dwmac *dwmac) static int meson_axg_set_phy_mode(struct meson8b_dwmac *dwmac) { - switch (dwmac->phy_mode) { - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_TXID: - /* enable RGMII mode */ - meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, - PRG_ETH0_EXT_PHY_MODE_MASK, - PRG_ETH0_EXT_RGMII_MODE); - break; - case PHY_INTERFACE_MODE_RMII: - /* disable RGMII mode -> enables RMII mode */ - meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, - PRG_ETH0_EXT_PHY_MODE_MASK, - PRG_ETH0_EXT_RMII_MODE); - break; - default: + int phy_intf_sel; + + phy_intf_sel = stmmac_get_phy_intf_sel(dwmac->phy_mode); + if (phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) { dev_err(dwmac->dev, "fail to set phy-mode %s\n", phy_modes(dwmac->phy_mode)); - return -EINVAL; + return phy_intf_sel < 0 ? phy_intf_sel : -EINVAL; } + meson8b_dwmac_mask_bits(dwmac, PRG_ETH0, PRG_ETH0_EXT_PHY_MODE_MASK, + FIELD_PREP(PRG_ETH0_EXT_PHY_MODE_MASK, + phy_intf_sel)); + return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index 0e4da216f942..0826a7bd32ff 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -76,10 +76,6 @@ #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) -/* MAC_CTRL_REG bits */ -#define ETHQOS_MAC_CTRL_SPEED_MODE BIT(14) -#define ETHQOS_MAC_CTRL_PORT_SEL BIT(15) - /* EMAC_WRAPPER_SGMII_PHY_CNTRL1 bits */ #define SGMII_PHY_CNTRL1_SGMII_TX_TO_RX_LOOPBACK_EN BIT(3) @@ -96,7 +92,6 @@ struct ethqos_emac_driver_data { bool rgmii_config_loopback_en; bool has_emac_ge_3; const char *link_clk_name; - bool has_integrated_pcs; u32 dma_addr_width; struct dwmac4_addrs dwmac4_addrs; bool needs_sgmii_loopback; @@ -106,12 +101,11 @@ struct qcom_ethqos { struct platform_device *pdev; void __iomem *rgmii_base; void __iomem *mac_base; - int (*configure_func)(struct qcom_ethqos *ethqos); + int (*configure_func)(struct qcom_ethqos *ethqos, int speed); unsigned int link_clk_rate; struct clk *link_clk; struct phy *serdes_phy; - int speed; int serdes_speed; phy_interface_t phy_mode; @@ -122,27 +116,39 @@ struct qcom_ethqos { bool needs_sgmii_loopback; }; -static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) +static u32 rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) { return readl(ethqos->rgmii_base + offset); } -static void rgmii_writel(struct qcom_ethqos *ethqos, - int value, unsigned int offset) +static void rgmii_writel(struct qcom_ethqos *ethqos, u32 value, + unsigned int offset) { writel(value, ethqos->rgmii_base + offset); } -static void rgmii_updatel(struct qcom_ethqos *ethqos, - int mask, int val, unsigned int offset) +static void rgmii_updatel(struct qcom_ethqos *ethqos, u32 mask, u32 val, + unsigned int offset) { - unsigned int temp; + u32 temp; temp = rgmii_readl(ethqos, offset); temp = (temp & ~(mask)) | val; rgmii_writel(ethqos, temp, offset); } +static void rgmii_setmask(struct qcom_ethqos *ethqos, u32 mask, + unsigned int offset) +{ + rgmii_updatel(ethqos, mask, mask, offset); +} + +static void rgmii_clrmask(struct qcom_ethqos *ethqos, u32 mask, + unsigned int offset) +{ + rgmii_updatel(ethqos, mask, 0, offset); +} + static void rgmii_dump(void *priv) { struct qcom_ethqos *ethqos = priv; @@ -200,8 +206,7 @@ qcom_ethqos_set_sgmii_loopback(struct qcom_ethqos *ethqos, bool enable) static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) { qcom_ethqos_set_sgmii_loopback(ethqos, true); - rgmii_updatel(ethqos, RGMII_CONFIG_FUNC_CLK_EN, - RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); + rgmii_setmask(ethqos, RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); } static const struct ethqos_emac_por emac_v2_3_0_por[] = { @@ -283,7 +288,6 @@ static const struct ethqos_emac_driver_data emac_v4_0_0_data = { .rgmii_config_loopback_en = false, .has_emac_ge_3 = true, .link_clk_name = "phyaux", - .has_integrated_pcs = true, .needs_sgmii_loopback = true, .dma_addr_width = 36, .dwmac4_addrs = { @@ -307,69 +311,55 @@ static const struct ethqos_emac_driver_data emac_v4_0_0_data = { static int ethqos_dll_configure(struct qcom_ethqos *ethqos) { struct device *dev = ðqos->pdev->dev; - unsigned int val; - int retry = 1000; + u32 val; /* Set CDR_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, - SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); /* Set CDR_EXT_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, - SDCC_DLL_CONFIG_CDR_EXT_EN, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, + SDCC_HC_REG_DLL_CONFIG); /* Clear CK_OUT_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, - 0, SDCC_HC_REG_DLL_CONFIG); + rgmii_clrmask(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, + SDCC_HC_REG_DLL_CONFIG); /* Set DLL_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, - SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); if (!ethqos->has_emac_ge_3) { - rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, - 0, SDCC_HC_REG_DLL_CONFIG); + rgmii_clrmask(ethqos, SDCC_DLL_MCLK_GATING_EN, + SDCC_HC_REG_DLL_CONFIG); - rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, - 0, SDCC_HC_REG_DLL_CONFIG); + rgmii_clrmask(ethqos, SDCC_DLL_CDR_FINE_PHASE, + SDCC_HC_REG_DLL_CONFIG); } /* Wait for CK_OUT_EN clear */ - do { - val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); - val &= SDCC_DLL_CONFIG_CK_OUT_EN; - if (!val) - break; - mdelay(1); - retry--; - } while (retry > 0); - if (!retry) + if (read_poll_timeout_atomic(rgmii_readl, val, + !(val & SDCC_DLL_CONFIG_CK_OUT_EN), + 1000, 1000000, false, + ethqos, SDCC_HC_REG_DLL_CONFIG)) dev_err(dev, "Clear CK_OUT_EN timedout\n"); /* Set CK_OUT_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, - SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, + SDCC_HC_REG_DLL_CONFIG); /* Wait for CK_OUT_EN set */ - retry = 1000; - do { - val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); - val &= SDCC_DLL_CONFIG_CK_OUT_EN; - if (val) - break; - mdelay(1); - retry--; - } while (retry > 0); - if (!retry) + if (read_poll_timeout_atomic(rgmii_readl, val, + val & SDCC_DLL_CONFIG_CK_OUT_EN, + 1000, 1000000, false, + ethqos, SDCC_HC_REG_DLL_CONFIG)) dev_err(dev, "Set CK_OUT_EN timedout\n"); /* Set DDR_CAL_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, - SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, + SDCC_HC_REG_DLL_CONFIG2); if (!ethqos->has_emac_ge_3) { - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, - 0, SDCC_HC_REG_DLL_CONFIG2); + rgmii_clrmask(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, + SDCC_HC_REG_DLL_CONFIG2); rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); @@ -377,15 +367,14 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, BIT(2), SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, - SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, + rgmii_setmask(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, SDCC_HC_REG_DLL_CONFIG2); } return 0; } -static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) +static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos, int speed) { struct device *dev = ðqos->pdev->dev; int phase_shift; @@ -399,8 +388,8 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) phase_shift = RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN; /* Disable loopback mode */ - rgmii_updatel(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_clrmask(ethqos, RGMII_CONFIG2_TX_TO_RX_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG2); /* Determine if this platform wants loopback enabled after programming */ if (ethqos->rgmii_config_loopback_en) @@ -409,29 +398,26 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) loopback = 0; /* Select RGMII, write 0 to interface select */ - rgmii_updatel(ethqos, RGMII_CONFIG_INTF_SEL, - 0, RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG_INTF_SEL, RGMII_IO_MACRO_CONFIG); - switch (ethqos->speed) { + switch (speed) { case SPEED_1000: - rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, - RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, - 0, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, - RGMII_CONFIG_POS_NEG_DATA_SEL, + rgmii_setmask(ethqos, RGMII_CONFIG_DDR_MODE, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, + RGMII_IO_MACRO_CONFIG); + rgmii_setmask(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, - RGMII_CONFIG_PROG_SWAP, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_setmask(ethqos, RGMII_CONFIG_PROG_SWAP, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, + RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, phase_shift, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, - 0, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_CONFIG2_RX_PROG_SWAP, + rgmii_clrmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, + RGMII_IO_MACRO_CONFIG2); + rgmii_setmask(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); /* PRG_RCLK_DLY = TCXO period * TCXO_CYCLES_CNT / 2 * RX delay ns, @@ -446,104 +432,95 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, 57, SDCC_HC_REG_DDR_CONFIG); } - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, - SDCC_DDR_CONFIG_PRG_DLY_EN, + rgmii_setmask(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_HC_REG_DDR_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, loopback, RGMII_IO_MACRO_CONFIG); break; case SPEED_100: - rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, - RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, - RGMII_CONFIG_BYPASS_TX_ID_EN, + rgmii_setmask(ethqos, RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, - 0, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_setmask(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG_PROG_SWAP, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, + RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, phase_shift, RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_2, BIT(6), RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_clrmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, + RGMII_IO_MACRO_CONFIG2); if (ethqos->has_emac_ge_3) - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_CONFIG2_RX_PROG_SWAP, + rgmii_setmask(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); else - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_clrmask(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, - SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, + rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, - SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, + rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, SDCC_HC_REG_DDR_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, loopback, RGMII_IO_MACRO_CONFIG); break; case SPEED_10: - rgmii_updatel(ethqos, RGMII_CONFIG_DDR_MODE, - RGMII_CONFIG_DDR_MODE, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, - RGMII_CONFIG_BYPASS_TX_ID_EN, + rgmii_setmask(ethqos, RGMII_CONFIG_DDR_MODE, + RGMII_IO_MACRO_CONFIG); + rgmii_setmask(ethqos, RGMII_CONFIG_BYPASS_TX_ID_EN, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_POS_NEG_DATA_SEL, - 0, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_clrmask(ethqos, RGMII_CONFIG_PROG_SWAP, + RGMII_IO_MACRO_CONFIG); + rgmii_clrmask(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, + RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, phase_shift, RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, BIT(12) | GENMASK(9, 8), RGMII_IO_MACRO_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_clrmask(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, + RGMII_IO_MACRO_CONFIG2); if (ethqos->has_emac_ge_3) - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - RGMII_CONFIG2_RX_PROG_SWAP, + rgmii_setmask(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, RGMII_IO_MACRO_CONFIG2); else - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + rgmii_clrmask(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, - SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, + rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY, SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, - SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, + rgmii_setmask(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, SDCC_HC_REG_DDR_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, loopback, RGMII_IO_MACRO_CONFIG); break; default: - dev_err(dev, "Invalid speed %d\n", ethqos->speed); + dev_err(dev, "Invalid speed %d\n", speed); return -EINVAL; } return 0; } -static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) +static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos, int speed) { struct device *dev = ðqos->pdev->dev; - volatile unsigned int dll_lock; - unsigned int i, retry = 1000; + unsigned int i; + u32 val; /* Reset to POR values and enable clk */ for (i = 0; i < ethqos->num_por; i++) @@ -554,15 +531,15 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) /* Initialize the DLL first */ /* Set DLL_RST */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, - SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_DLL_RST, + SDCC_HC_REG_DLL_CONFIG); /* Set PDN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, - SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_PDN, + SDCC_HC_REG_DLL_CONFIG); if (ethqos->has_emac_ge_3) { - if (ethqos->speed == SPEED_1000) { + if (speed == SPEED_1000) { rgmii_writel(ethqos, 0x1800000, SDCC_TEST_CTL); rgmii_writel(ethqos, 0x2C010800, SDCC_USR_CTL); rgmii_writel(ethqos, 0xA001, SDCC_HC_REG_DLL_CONFIG2); @@ -573,21 +550,18 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) } /* Clear DLL_RST */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_RST, 0, - SDCC_HC_REG_DLL_CONFIG); + rgmii_clrmask(ethqos, SDCC_DLL_CONFIG_DLL_RST, SDCC_HC_REG_DLL_CONFIG); /* Clear PDN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_PDN, 0, - SDCC_HC_REG_DLL_CONFIG); + rgmii_clrmask(ethqos, SDCC_DLL_CONFIG_PDN, SDCC_HC_REG_DLL_CONFIG); - if (ethqos->speed != SPEED_100 && ethqos->speed != SPEED_10) { + if (speed != SPEED_100 && speed != SPEED_10) { /* Set DLL_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, - SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_DLL_EN, + SDCC_HC_REG_DLL_CONFIG); /* Set CK_OUT_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, - SDCC_DLL_CONFIG_CK_OUT_EN, + rgmii_setmask(ethqos, SDCC_DLL_CONFIG_CK_OUT_EN, SDCC_HC_REG_DLL_CONFIG); /* Set USR_CTL bit 26 with mask of 3 bits */ @@ -596,21 +570,17 @@ static int ethqos_configure_rgmii(struct qcom_ethqos *ethqos) SDCC_USR_CTL); /* wait for DLL LOCK */ - do { - mdelay(1); - dll_lock = rgmii_readl(ethqos, SDC4_STATUS); - if (dll_lock & SDC4_STATUS_DLL_LOCK) - break; - retry--; - } while (retry > 0); - if (!retry) + if (read_poll_timeout_atomic(rgmii_readl, val, + val & SDC4_STATUS_DLL_LOCK, + 1000, 1000000, true, + ethqos, SDC4_STATUS)) dev_err(dev, "Timeout while waiting for DLL lock\n"); } - if (ethqos->speed == SPEED_1000) + if (speed == SPEED_1000) ethqos_dll_configure(ethqos); - ethqos_rgmii_macro_init(ethqos); + ethqos_rgmii_macro_init(ethqos, speed); return 0; } @@ -623,67 +593,52 @@ static void ethqos_set_serdes_speed(struct qcom_ethqos *ethqos, int speed) } } +static void ethqos_pcs_set_inband(struct stmmac_priv *priv, bool enable) +{ + stmmac_pcs_ctrl_ane(priv, enable, 0); +} + /* On interface toggle MAC registers gets reset. * Configure MAC block for SGMII on ethernet phy link up */ -static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos) +static int ethqos_configure_sgmii(struct qcom_ethqos *ethqos, int speed) { struct net_device *dev = platform_get_drvdata(ethqos->pdev); struct stmmac_priv *priv = netdev_priv(dev); - int val; - - val = readl(ethqos->mac_base + MAC_CTRL_REG); - switch (ethqos->speed) { + switch (speed) { case SPEED_2500: - val &= ~ETHQOS_MAC_CTRL_PORT_SEL; - rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, - RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + rgmii_setmask(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_IO_MACRO_CONFIG2); ethqos_set_serdes_speed(ethqos, SPEED_2500); - stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 0, 0, 0); + ethqos_pcs_set_inband(priv, false); break; case SPEED_1000: - val &= ~ETHQOS_MAC_CTRL_PORT_SEL; - rgmii_updatel(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, - RGMII_CONFIG2_RGMII_CLK_SEL_CFG, + rgmii_setmask(ethqos, RGMII_CONFIG2_RGMII_CLK_SEL_CFG, RGMII_IO_MACRO_CONFIG2); ethqos_set_serdes_speed(ethqos, SPEED_1000); - stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); + ethqos_pcs_set_inband(priv, true); break; case SPEED_100: - val |= ETHQOS_MAC_CTRL_PORT_SEL | ETHQOS_MAC_CTRL_SPEED_MODE; ethqos_set_serdes_speed(ethqos, SPEED_1000); - stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); + ethqos_pcs_set_inband(priv, true); break; case SPEED_10: - val |= ETHQOS_MAC_CTRL_PORT_SEL; - val &= ~ETHQOS_MAC_CTRL_SPEED_MODE; rgmii_updatel(ethqos, RGMII_CONFIG_SGMII_CLK_DVDR, FIELD_PREP(RGMII_CONFIG_SGMII_CLK_DVDR, SGMII_10M_RX_CLK_DVDR), RGMII_IO_MACRO_CONFIG); ethqos_set_serdes_speed(ethqos, SPEED_1000); - stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, 0, 0); + ethqos_pcs_set_inband(priv, true); break; } - writel(val, ethqos->mac_base + MAC_CTRL_REG); - - return val; -} - -static void qcom_ethqos_speed_mode_2500(struct net_device *ndev, void *data) -{ - struct stmmac_priv *priv = netdev_priv(ndev); - - priv->plat->max_speed = 2500; - priv->plat->phy_interface = PHY_INTERFACE_MODE_2500BASEX; + return 0; } -static int ethqos_configure(struct qcom_ethqos *ethqos) +static int ethqos_configure(struct qcom_ethqos *ethqos, int speed) { - return ethqos->configure_func(ethqos); + return ethqos->configure_func(ethqos, speed); } static void ethqos_fix_mac_speed(void *priv, int speed, unsigned int mode) @@ -691,9 +646,8 @@ static void ethqos_fix_mac_speed(void *priv, int speed, unsigned int mode) struct qcom_ethqos *ethqos = priv; qcom_ethqos_set_sgmii_loopback(ethqos, false); - ethqos->speed = speed; ethqos_update_link_clk(ethqos, speed); - ethqos_configure(ethqos); + ethqos_configure(ethqos, speed); } static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv) @@ -709,7 +663,7 @@ static int qcom_ethqos_serdes_powerup(struct net_device *ndev, void *priv) if (ret) return ret; - return phy_set_speed(ethqos->serdes_phy, ethqos->speed); + return phy_set_speed(ethqos->serdes_phy, ethqos->serdes_speed); } static void qcom_ethqos_serdes_powerdown(struct net_device *ndev, void *priv) @@ -803,8 +757,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev) ethqos->configure_func = ethqos_configure_rgmii; break; case PHY_INTERFACE_MODE_2500BASEX: - plat_dat->speed_mode_2500 = qcom_ethqos_speed_mode_2500; - fallthrough; case PHY_INTERFACE_MODE_SGMII: ethqos->configure_func = ethqos_configure_sgmii; break; @@ -847,7 +799,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(ethqos->serdes_phy), "Failed to get serdes phy\n"); - ethqos->speed = SPEED_1000; ethqos->serdes_speed = SPEED_1000; ethqos_update_link_clk(ethqos, SPEED_1000); ethqos_set_func_clk_en(ethqos); @@ -856,7 +807,7 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->fix_mac_speed = ethqos_fix_mac_speed; plat_dat->dump_debug_regs = rgmii_dump; plat_dat->ptp_clk_freq_config = ethqos_ptp_clk_freq_config; - plat_dat->has_gmac4 = 1; + plat_dat->core_type = DWMAC_CORE_GMAC4; if (ethqos->has_emac_ge_3) plat_dat->dwmac4_addrs = &data->dwmac4_addrs; plat_dat->pmt = 1; @@ -864,8 +815,6 @@ static int qcom_ethqos_probe(struct platform_device *pdev) plat_dat->flags |= STMMAC_FLAG_TSO_EN; if (of_device_is_compatible(np, "qcom,qcs404-ethqos")) plat_dat->flags |= STMMAC_FLAG_RX_CLK_RUNS_IN_LPI; - if (data->has_integrated_pcs) - plat_dat->flags |= STMMAC_FLAG_HAS_INTEGRATED_PCS; if (data->dma_addr_width) plat_dat->host_dma_width = data->dma_addr_width; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c new file mode 100644 index 000000000000..be7f5eb2cdcf --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-renesas-gbeth.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * dwmac-renesas-gbeth.c - DWMAC Specific Glue layer for Renesas GBETH + * + * The Rx and Tx clocks are supplied as follows for the GBETH IP. + * + * Rx / Tx + * -------+------------- on / off ------- + * | + * | Rx-180 / Tx-180 + * +---- not ---- on / off ------- + * + * Copyright (C) 2025 Renesas Electronics Corporation + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pcs-rzn1-miic.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/types.h> + +#include "stmmac_platform.h" + +/** + * struct renesas_gbeth_of_data - OF data for Renesas GBETH + * + * @clks: Array of clock names + * @num_clks: Number of clocks + * @stmmac_flags: Flags for the stmmac driver + * @handle_reset: Flag to indicate if reset control is + * handled by the glue driver or core driver. + * @set_clk_tx_rate: Flag to indicate if Tx clock is fixed or + * set_clk_tx_rate is needed. + * @has_pcs: Flag to indicate if the MAC has a PCS + */ +struct renesas_gbeth_of_data { + const char * const *clks; + u8 num_clks; + u32 stmmac_flags; + bool handle_reset; + bool set_clk_tx_rate; + bool has_pcs; +}; + +struct renesas_gbeth { + const struct renesas_gbeth_of_data *of_data; + struct plat_stmmacenet_data *plat_dat; + struct reset_control *rstc; + struct device *dev; +}; + +static const char *const renesas_gbeth_clks[] = { + "tx", "tx-180", "rx", "rx-180", +}; + +static const char *const renesas_gmac_clks[] = { + "tx", +}; + +static int renesas_gmac_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 renesas_gmac_pcs_exit(struct stmmac_priv *priv) +{ + if (priv->hw->phylink_pcs) + miic_destroy(priv->hw->phylink_pcs); +} + +static struct phylink_pcs *renesas_gmac_select_pcs(struct stmmac_priv *priv, + phy_interface_t interface) +{ + return priv->hw->phylink_pcs; +} + +static int renesas_gbeth_init(struct device *dev, void *priv) +{ + struct plat_stmmacenet_data *plat_dat; + struct renesas_gbeth *gbeth = priv; + int ret; + + plat_dat = gbeth->plat_dat; + + ret = reset_control_deassert(gbeth->rstc); + if (ret) { + dev_err(gbeth->dev, "Reset deassert failed\n"); + return ret; + } + + ret = clk_bulk_prepare_enable(plat_dat->num_clks, + plat_dat->clks); + if (ret) + reset_control_assert(gbeth->rstc); + + return ret; +} + +static void renesas_gbeth_exit(struct device *dev, void *priv) +{ + struct plat_stmmacenet_data *plat_dat; + struct renesas_gbeth *gbeth = priv; + int ret; + + plat_dat = gbeth->plat_dat; + + clk_bulk_disable_unprepare(plat_dat->num_clks, plat_dat->clks); + + ret = reset_control_assert(gbeth->rstc); + if (ret) + dev_err(gbeth->dev, "Reset assert failed\n"); +} + +static int renesas_gbeth_probe(struct platform_device *pdev) +{ + const struct renesas_gbeth_of_data *of_data; + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct device *dev = &pdev->dev; + struct renesas_gbeth *gbeth; + unsigned int i; + int err; + + err = stmmac_get_platform_resources(pdev, &stmmac_res); + if (err) + return dev_err_probe(dev, err, + "failed to get resources\n"); + + plat_dat = devm_stmmac_probe_config_dt(pdev, stmmac_res.mac); + if (IS_ERR(plat_dat)) + return dev_err_probe(dev, PTR_ERR(plat_dat), + "dt configuration failed\n"); + + gbeth = devm_kzalloc(dev, sizeof(*gbeth), GFP_KERNEL); + if (!gbeth) + return -ENOMEM; + + of_data = of_device_get_match_data(&pdev->dev); + gbeth->of_data = of_data; + + plat_dat->num_clks = of_data->num_clks; + plat_dat->clks = devm_kcalloc(dev, plat_dat->num_clks, + sizeof(*plat_dat->clks), GFP_KERNEL); + if (!plat_dat->clks) + return -ENOMEM; + + for (i = 0; i < plat_dat->num_clks; i++) + plat_dat->clks[i].id = of_data->clks[i]; + + err = devm_clk_bulk_get(dev, plat_dat->num_clks, plat_dat->clks); + if (err < 0) + return err; + + plat_dat->clk_tx_i = stmmac_pltfr_find_clk(plat_dat, "tx"); + if (!plat_dat->clk_tx_i) + return dev_err_probe(dev, -EINVAL, + "error finding tx clock\n"); + + if (of_data->handle_reset) { + gbeth->rstc = devm_reset_control_get_exclusive(dev, NULL); + if (IS_ERR(gbeth->rstc)) + return PTR_ERR(gbeth->rstc); + } + + gbeth->dev = dev; + gbeth->plat_dat = plat_dat; + plat_dat->bsp_priv = gbeth; + if (of_data->set_clk_tx_rate) + plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; + plat_dat->init = renesas_gbeth_init; + plat_dat->exit = renesas_gbeth_exit; + plat_dat->flags |= STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP | + gbeth->of_data->stmmac_flags; + if (of_data->has_pcs) { + plat_dat->pcs_init = renesas_gmac_pcs_init; + plat_dat->pcs_exit = renesas_gmac_pcs_exit; + plat_dat->select_pcs = renesas_gmac_select_pcs; + } + + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); +} + +static const struct renesas_gbeth_of_data renesas_gbeth_of_data = { + .clks = renesas_gbeth_clks, + .num_clks = ARRAY_SIZE(renesas_gbeth_clks), + .handle_reset = true, + .set_clk_tx_rate = true, + .stmmac_flags = STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY | + STMMAC_FLAG_SPH_DISABLE, +}; + +static const struct renesas_gbeth_of_data renesas_gmac_of_data = { + .clks = renesas_gmac_clks, + .num_clks = ARRAY_SIZE(renesas_gmac_clks), + .stmmac_flags = STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY, + .has_pcs = true, +}; + +static const struct of_device_id renesas_gbeth_match[] = { + { .compatible = "renesas,r9a09g077-gbeth", .data = &renesas_gmac_of_data }, + { .compatible = "renesas,rzv2h-gbeth", .data = &renesas_gbeth_of_data }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, renesas_gbeth_match); + +static struct platform_driver renesas_gbeth_driver = { + .probe = renesas_gbeth_probe, + .driver = { + .name = "renesas-gbeth", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = renesas_gbeth_match, + }, +}; +module_platform_driver(renesas_gbeth_driver); + +MODULE_AUTHOR("Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>"); +MODULE_DESCRIPTION("Renesas GBETH DWMAC Specific Glue layer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 700858ff6f7c..0a95f54e725e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -8,6 +8,7 @@ */ #include <linux/stmmac.h> +#include <linux/hw_bitfield.h> #include <linux/bitops.h> #include <linux/clk.h> #include <linux/phy.h> @@ -24,12 +25,21 @@ #include "stmmac_platform.h" struct rk_priv_data; + +struct rk_reg_speed_data { + unsigned int rgmii_10; + unsigned int rgmii_100; + unsigned int rgmii_1000; + unsigned int rmii_10; + unsigned int rmii_100; +}; + struct rk_gmac_ops { void (*set_to_rgmii)(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay); void (*set_to_rmii)(struct rk_priv_data *bsp_priv); - void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed); - void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed); + int (*set_speed)(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed); void (*set_clock_selection)(struct rk_priv_data *bsp_priv, bool input, bool enable); void (*integrated_phy_powerup)(struct rk_priv_data *bsp_priv); @@ -58,11 +68,10 @@ enum rk_clocks_index { }; struct rk_priv_data { - struct platform_device *pdev; + struct device *dev; phy_interface_t phy_iface; int id; struct regulator *regulator; - bool suspended; const struct rk_gmac_ops *ops; bool clk_enabled; @@ -71,7 +80,6 @@ struct rk_priv_data { struct clk_bulk_data *clks; int num_clks; - struct clk *clk_mac; struct clk *clk_phy; struct reset_control *phy_reset; @@ -83,11 +91,71 @@ struct rk_priv_data { struct regmap *php_grf; }; -#define HIWORD_UPDATE(val, mask, shift) \ - ((val) << (shift) | (mask) << ((shift) + 16)) +static int rk_set_reg_speed(struct rk_priv_data *bsp_priv, + const struct rk_reg_speed_data *rsd, + unsigned int reg, phy_interface_t interface, + int speed) +{ + unsigned int val; + + if (phy_interface_mode_is_rgmii(interface)) { + if (speed == SPEED_10) { + val = rsd->rgmii_10; + } else if (speed == SPEED_100) { + val = rsd->rgmii_100; + } else if (speed == SPEED_1000) { + val = rsd->rgmii_1000; + } else { + /* Phylink will not allow inappropriate speeds for + * interface modes, so this should never happen. + */ + return -EINVAL; + } + } else if (interface == PHY_INTERFACE_MODE_RMII) { + if (speed == SPEED_10) { + val = rsd->rmii_10; + } else if (speed == SPEED_100) { + val = rsd->rmii_100; + } else { + /* Phylink will not allow inappropriate speeds for + * interface modes, so this should never happen. + */ + return -EINVAL; + } + } else { + /* This should never happen, as .get_interfaces() limits + * the interface modes that are supported to RGMII and/or + * RMII. + */ + return -EINVAL; + } + + regmap_write(bsp_priv->grf, reg, val); + + return 0; + +} + +static int rk_set_clk_mac_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) +{ + struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk; + long rate; + + rate = rgmii_clock(speed); + if (rate < 0) + return rate; -#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16)) -#define GRF_CLR_BIT(nr) (BIT(nr+16)) + return clk_set_rate(clk_mac_speed, rate); +} + +#define GRF_FIELD(hi, lo, val) \ + FIELD_PREP_WM16(GENMASK_U16(hi, lo), val) +#define GRF_FIELD_CONST(hi, lo, val) \ + FIELD_PREP_WM16_CONST(GENMASK_U16(hi, lo), val) + +#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16)) +#define GRF_CLR_BIT(nr) (BIT(nr+16)) #define DELAY_ENABLE(soc, tx, rx) \ (((tx) ? soc##_GMAC_TXCLK_DLY_ENABLE : soc##_GMAC_TXCLK_DLY_DISABLE) | \ @@ -101,9 +169,9 @@ struct rk_priv_data { #define RK_MACPHY_ENABLE GRF_BIT(0) #define RK_MACPHY_DISABLE GRF_CLR_BIT(0) #define RK_MACPHY_CFG_CLK_50M GRF_BIT(14) -#define RK_GMAC2PHY_RMII_MODE (GRF_BIT(6) | GRF_CLR_BIT(7)) -#define RK_GRF_CON2_MACPHY_ID HIWORD_UPDATE(0x1234, 0xffff, 0) -#define RK_GRF_CON3_MACPHY_ID HIWORD_UPDATE(0x35, 0x3f, 0) +#define RK_GMAC2PHY_RMII_MODE GRF_FIELD(7, 6, 1) +#define RK_GRF_CON2_MACPHY_ID GRF_FIELD(15, 0, 0x1234) +#define RK_GRF_CON3_MACPHY_ID GRF_FIELD(5, 0, 0x35) static void rk_gmac_integrated_ephy_powerup(struct rk_priv_data *priv) { @@ -137,7 +205,7 @@ static void rk_gmac_integrated_ephy_powerdown(struct rk_priv_data *priv) #define RK_FEPHY_SHUTDOWN GRF_BIT(1) #define RK_FEPHY_POWERUP GRF_CLR_BIT(1) #define RK_FEPHY_INTERNAL_RMII_SEL GRF_BIT(6) -#define RK_FEPHY_24M_CLK_SEL (GRF_BIT(8) | GRF_BIT(9)) +#define RK_FEPHY_24M_CLK_SEL GRF_FIELD(9, 8, 3) #define RK_FEPHY_PHY_ID GRF_BIT(11) static void rk_gmac_integrated_fephy_powerup(struct rk_priv_data *priv, @@ -166,53 +234,48 @@ static void rk_gmac_integrated_fephy_powerdown(struct rk_priv_data *priv, #define PX30_GRF_GMAC_CON1 0x0904 /* PX30_GRF_GMAC_CON1 */ -#define PX30_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | \ - GRF_BIT(6)) +#define PX30_GMAC_PHY_INTF_SEL(val) GRF_FIELD(6, 4, val) #define PX30_GMAC_SPEED_10M GRF_CLR_BIT(2) #define PX30_GMAC_SPEED_100M GRF_BIT(2) static void px30_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1, - PX30_GMAC_PHY_INTF_SEL_RMII); + PX30_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII)); } -static void px30_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int px30_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk; - struct device *dev = &bsp_priv->pdev->dev; - int ret; + struct device *dev = bsp_priv->dev; + unsigned int con1; + long rate; if (!clk_mac_speed) { dev_err(dev, "%s: Missing clk_mac_speed clock\n", __func__); - return; + return -EINVAL; } if (speed == 10) { - regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1, - PX30_GMAC_SPEED_10M); - - ret = clk_set_rate(clk_mac_speed, 2500000); - if (ret) - dev_err(dev, "%s: set clk_mac_speed rate 2500000 failed: %d\n", - __func__, ret); + con1 = PX30_GMAC_SPEED_10M; + rate = 2500000; } else if (speed == 100) { - regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1, - PX30_GMAC_SPEED_100M); - - ret = clk_set_rate(clk_mac_speed, 25000000); - if (ret) - dev_err(dev, "%s: set clk_mac_speed rate 25000000 failed: %d\n", - __func__, ret); - + con1 = PX30_GMAC_SPEED_100M; + rate = 25000000; } else { dev_err(dev, "unknown speed value for RMII! speed=%d", speed); + return -EINVAL; } + + regmap_write(bsp_priv->grf, PX30_GRF_GMAC_CON1, con1); + + return clk_set_rate(clk_mac_speed, rate); } static const struct rk_gmac_ops px30_ops = { .set_to_rmii = px30_set_to_rmii, - .set_rmii_speed = px30_set_rmii_speed, + .set_speed = px30_set_speed, }; #define RK3128_GRF_MAC_CON0 0x0168 @@ -223,23 +286,20 @@ static const struct rk_gmac_ops px30_ops = { #define RK3128_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) #define RK3128_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) #define RK3128_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -#define RK3128_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) -#define RK3128_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3128_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(13, 7, val) +#define RK3128_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) /* RK3128_GRF_MAC_CON1 */ -#define RK3128_GMAC_PHY_INTF_SEL_RGMII \ - (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8)) -#define RK3128_GMAC_PHY_INTF_SEL_RMII \ - (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8)) +#define RK3128_GMAC_PHY_INTF_SEL(val) GRF_FIELD(8, 6, val) #define RK3128_GMAC_FLOW_CTRL GRF_BIT(9) #define RK3128_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9) #define RK3128_GMAC_SPEED_10M GRF_CLR_BIT(10) #define RK3128_GMAC_SPEED_100M GRF_BIT(10) #define RK3128_GMAC_RMII_CLK_25M GRF_BIT(11) #define RK3128_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11) -#define RK3128_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13)) -#define RK3128_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13)) -#define RK3128_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13)) +#define RK3128_GMAC_CLK_125M GRF_FIELD_CONST(13, 12, 0) +#define RK3128_GMAC_CLK_25M GRF_FIELD_CONST(13, 12, 3) +#define RK3128_GMAC_CLK_2_5M GRF_FIELD_CONST(13, 12, 2) #define RK3128_GMAC_RMII_MODE GRF_BIT(14) #define RK3128_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) @@ -247,7 +307,7 @@ static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_PHY_INTF_SEL_RGMII | + RK3128_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3128_GMAC_RMII_MODE_CLR); regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON0, DELAY_ENABLE(RK3128, tx_delay, rx_delay) | @@ -258,48 +318,29 @@ static void rk3128_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3128_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_PHY_INTF_SEL_RMII | RK3128_GMAC_RMII_MODE); + RK3128_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | + RK3128_GMAC_RMII_MODE); } -static void rk3128_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3128_reg_speed_data = { + .rgmii_10 = RK3128_GMAC_CLK_2_5M, + .rgmii_100 = RK3128_GMAC_CLK_25M, + .rgmii_1000 = RK3128_GMAC_CLK_125M, + .rmii_10 = RK3128_GMAC_RMII_CLK_2_5M | RK3128_GMAC_SPEED_10M, + .rmii_100 = RK3128_GMAC_RMII_CLK_25M | RK3128_GMAC_SPEED_100M, +}; -static void rk3128_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3128_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) { - regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_RMII_CLK_2_5M | - RK3128_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RK3128_GRF_MAC_CON1, - RK3128_GMAC_RMII_CLK_25M | - RK3128_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } + return rk_set_reg_speed(bsp_priv, &rk3128_reg_speed_data, + RK3128_GRF_MAC_CON1, interface, speed); } static const struct rk_gmac_ops rk3128_ops = { .set_to_rgmii = rk3128_set_to_rgmii, .set_to_rmii = rk3128_set_to_rmii, - .set_rgmii_speed = rk3128_set_rgmii_speed, - .set_rmii_speed = rk3128_set_rmii_speed, + .set_speed = rk3128_set_speed, }; #define RK3228_GRF_MAC_CON0 0x0900 @@ -308,23 +349,20 @@ static const struct rk_gmac_ops rk3128_ops = { #define RK3228_GRF_CON_MUX 0x50 /* RK3228_GRF_MAC_CON0 */ -#define RK3228_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) -#define RK3228_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3228_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(13, 7, val) +#define RK3228_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) /* RK3228_GRF_MAC_CON1 */ -#define RK3228_GMAC_PHY_INTF_SEL_RGMII \ - (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6)) -#define RK3228_GMAC_PHY_INTF_SEL_RMII \ - (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RK3228_GMAC_PHY_INTF_SEL(val) GRF_FIELD(6, 4, val) #define RK3228_GMAC_FLOW_CTRL GRF_BIT(3) #define RK3228_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3) #define RK3228_GMAC_SPEED_10M GRF_CLR_BIT(2) #define RK3228_GMAC_SPEED_100M GRF_BIT(2) #define RK3228_GMAC_RMII_CLK_25M GRF_BIT(7) #define RK3228_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7) -#define RK3228_GMAC_CLK_125M (GRF_CLR_BIT(8) | GRF_CLR_BIT(9)) -#define RK3228_GMAC_CLK_25M (GRF_BIT(8) | GRF_BIT(9)) -#define RK3228_GMAC_CLK_2_5M (GRF_CLR_BIT(8) | GRF_BIT(9)) +#define RK3228_GMAC_CLK_125M GRF_FIELD_CONST(9, 8, 0) +#define RK3228_GMAC_CLK_25M GRF_FIELD_CONST(9, 8, 3) +#define RK3228_GMAC_CLK_2_5M GRF_FIELD_CONST(9, 8, 2) #define RK3228_GMAC_RMII_MODE GRF_BIT(10) #define RK3228_GMAC_RMII_MODE_CLR GRF_CLR_BIT(10) #define RK3228_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0) @@ -339,7 +377,7 @@ static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_PHY_INTF_SEL_RGMII | + RK3228_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3228_GMAC_RMII_MODE_CLR | DELAY_ENABLE(RK3228, tx_delay, rx_delay)); @@ -351,44 +389,26 @@ static void rk3228_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3228_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_PHY_INTF_SEL_RMII | + RK3228_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | RK3228_GMAC_RMII_MODE); /* set MAC to RMII mode */ regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, GRF_BIT(11)); } -static void rk3228_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3228_reg_speed_data = { + .rgmii_10 = RK3228_GMAC_CLK_2_5M, + .rgmii_100 = RK3228_GMAC_CLK_25M, + .rgmii_1000 = RK3228_GMAC_CLK_125M, + .rmii_10 = RK3228_GMAC_RMII_CLK_2_5M | RK3228_GMAC_SPEED_10M, + .rmii_100 = RK3228_GMAC_RMII_CLK_25M | RK3228_GMAC_SPEED_100M, +}; -static void rk3228_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3228_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_RMII_CLK_2_5M | - RK3228_GMAC_SPEED_10M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3228_GRF_MAC_CON1, - RK3228_GMAC_RMII_CLK_25M | - RK3228_GMAC_SPEED_100M); - else - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); + return rk_set_reg_speed(bsp_priv, &rk3228_reg_speed_data, + RK3228_GRF_MAC_CON1, interface, speed); } static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv) @@ -402,8 +422,7 @@ static void rk3228_integrated_phy_powerup(struct rk_priv_data *priv) static const struct rk_gmac_ops rk3228_ops = { .set_to_rgmii = rk3228_set_to_rgmii, .set_to_rmii = rk3228_set_to_rmii, - .set_rgmii_speed = rk3228_set_rgmii_speed, - .set_rmii_speed = rk3228_set_rmii_speed, + .set_speed = rk3228_set_speed, .integrated_phy_powerup = rk3228_integrated_phy_powerup, .integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown, }; @@ -412,19 +431,16 @@ static const struct rk_gmac_ops rk3228_ops = { #define RK3288_GRF_SOC_CON3 0x0250 /*RK3288_GRF_SOC_CON1*/ -#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \ - GRF_CLR_BIT(8)) -#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \ - GRF_BIT(8)) +#define RK3288_GMAC_PHY_INTF_SEL(val) GRF_FIELD(8, 6, val) #define RK3288_GMAC_FLOW_CTRL GRF_BIT(9) #define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9) #define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10) #define RK3288_GMAC_SPEED_100M GRF_BIT(10) #define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11) #define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11) -#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13)) -#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13)) -#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13)) +#define RK3288_GMAC_CLK_125M GRF_FIELD_CONST(13, 12, 0) +#define RK3288_GMAC_CLK_25M GRF_FIELD_CONST(13, 12, 3) +#define RK3288_GMAC_CLK_2_5M GRF_FIELD_CONST(13, 12, 2) #define RK3288_GMAC_RMII_MODE GRF_BIT(14) #define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) @@ -433,14 +449,14 @@ static const struct rk_gmac_ops rk3228_ops = { #define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) #define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) #define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) -#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3288_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(13, 7, val) +#define RK3288_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_PHY_INTF_SEL_RGMII | + RK3288_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3288_GMAC_RMII_MODE_CLR); regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3, DELAY_ENABLE(RK3288, tx_delay, rx_delay) | @@ -451,55 +467,35 @@ static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE); + RK3288_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | + RK3288_GMAC_RMII_MODE); } -static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3288_reg_speed_data = { + .rgmii_10 = RK3288_GMAC_CLK_2_5M, + .rgmii_100 = RK3288_GMAC_CLK_25M, + .rgmii_1000 = RK3288_GMAC_CLK_125M, + .rmii_10 = RK3288_GMAC_RMII_CLK_2_5M | RK3288_GMAC_SPEED_10M, + .rmii_100 = RK3288_GMAC_RMII_CLK_25M | RK3288_GMAC_SPEED_100M, +}; -static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3288_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) { - regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_RMII_CLK_2_5M | - RK3288_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, - RK3288_GMAC_RMII_CLK_25M | - RK3288_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } + return rk_set_reg_speed(bsp_priv, &rk3288_reg_speed_data, + RK3288_GRF_SOC_CON1, interface, speed); } static const struct rk_gmac_ops rk3288_ops = { .set_to_rgmii = rk3288_set_to_rgmii, .set_to_rmii = rk3288_set_to_rmii, - .set_rgmii_speed = rk3288_set_rgmii_speed, - .set_rmii_speed = rk3288_set_rmii_speed, + .set_speed = rk3288_set_speed, }; #define RK3308_GRF_MAC_CON0 0x04a0 /* RK3308_GRF_MAC_CON0 */ -#define RK3308_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(2) | GRF_CLR_BIT(3) | \ - GRF_BIT(4)) +#define RK3308_GMAC_PHY_INTF_SEL(val) GRF_FIELD(4, 2, val) #define RK3308_GMAC_FLOW_CTRL GRF_BIT(3) #define RK3308_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3) #define RK3308_GMAC_SPEED_10M GRF_CLR_BIT(0) @@ -508,27 +504,24 @@ static const struct rk_gmac_ops rk3288_ops = { static void rk3308_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0, - RK3308_GMAC_PHY_INTF_SEL_RMII); + RK3308_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII)); } -static void rk3308_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; +static const struct rk_reg_speed_data rk3308_reg_speed_data = { + .rmii_10 = RK3308_GMAC_SPEED_10M, + .rmii_100 = RK3308_GMAC_SPEED_100M, +}; - if (speed == 10) { - regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0, - RK3308_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RK3308_GRF_MAC_CON0, - RK3308_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } +static int rk3308_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) +{ + return rk_set_reg_speed(bsp_priv, &rk3308_reg_speed_data, + RK3308_GRF_MAC_CON0, interface, speed); } static const struct rk_gmac_ops rk3308_ops = { .set_to_rmii = rk3308_set_to_rmii, - .set_rmii_speed = rk3308_set_rmii_speed, + .set_speed = rk3308_set_speed, }; #define RK3328_GRF_MAC_CON0 0x0900 @@ -537,29 +530,24 @@ static const struct rk_gmac_ops rk3308_ops = { #define RK3328_GRF_MACPHY_CON1 0xb04 /* RK3328_GRF_MAC_CON0 */ -#define RK3328_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) -#define RK3328_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3328_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(13, 7, val) +#define RK3328_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) /* RK3328_GRF_MAC_CON1 */ -#define RK3328_GMAC_PHY_INTF_SEL_RGMII \ - (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6)) -#define RK3328_GMAC_PHY_INTF_SEL_RMII \ - (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RK3328_GMAC_PHY_INTF_SEL(val) GRF_FIELD(6, 4, val) #define RK3328_GMAC_FLOW_CTRL GRF_BIT(3) #define RK3328_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3) #define RK3328_GMAC_SPEED_10M GRF_CLR_BIT(2) #define RK3328_GMAC_SPEED_100M GRF_BIT(2) #define RK3328_GMAC_RMII_CLK_25M GRF_BIT(7) #define RK3328_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(7) -#define RK3328_GMAC_CLK_125M (GRF_CLR_BIT(11) | GRF_CLR_BIT(12)) -#define RK3328_GMAC_CLK_25M (GRF_BIT(11) | GRF_BIT(12)) -#define RK3328_GMAC_CLK_2_5M (GRF_CLR_BIT(11) | GRF_BIT(12)) +#define RK3328_GMAC_CLK_125M GRF_FIELD_CONST(12, 11, 0) +#define RK3328_GMAC_CLK_25M GRF_FIELD_CONST(12, 11, 3) +#define RK3328_GMAC_CLK_2_5M GRF_FIELD_CONST(12, 11, 2) #define RK3328_GMAC_RMII_MODE GRF_BIT(9) #define RK3328_GMAC_RMII_MODE_CLR GRF_CLR_BIT(9) #define RK3328_GMAC_TXCLK_DLY_ENABLE GRF_BIT(0) -#define RK3328_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0) #define RK3328_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1) -#define RK3328_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(0) /* RK3328_GRF_MACPHY_CON1 */ #define RK3328_MACPHY_RMII_MODE GRF_BIT(9) @@ -568,7 +556,7 @@ static void rk3328_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1, - RK3328_GMAC_PHY_INTF_SEL_RGMII | + RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3328_GMAC_RMII_MODE_CLR | RK3328_GMAC_RXCLK_DLY_ENABLE | RK3328_GMAC_TXCLK_DLY_ENABLE); @@ -586,45 +574,30 @@ static void rk3328_set_to_rmii(struct rk_priv_data *bsp_priv) RK3328_GRF_MAC_CON1; regmap_write(bsp_priv->grf, reg, - RK3328_GMAC_PHY_INTF_SEL_RMII | + RK3328_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | RK3328_GMAC_RMII_MODE); } -static void rk3328_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1, - RK3328_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1, - RK3328_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3328_GRF_MAC_CON1, - RK3328_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3328_reg_speed_data = { + .rgmii_10 = RK3328_GMAC_CLK_2_5M, + .rgmii_100 = RK3328_GMAC_CLK_25M, + .rgmii_1000 = RK3328_GMAC_CLK_125M, + .rmii_10 = RK3328_GMAC_RMII_CLK_2_5M | RK3328_GMAC_SPEED_10M, + .rmii_100 = RK3328_GMAC_RMII_CLK_25M | RK3328_GMAC_SPEED_100M, +}; -static void rk3328_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3328_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; unsigned int reg; - reg = bsp_priv->integrated_phy ? RK3328_GRF_MAC_CON2 : - RK3328_GRF_MAC_CON1; - - if (speed == 10) - regmap_write(bsp_priv->grf, reg, - RK3328_GMAC_RMII_CLK_2_5M | - RK3328_GMAC_SPEED_10M); - else if (speed == 100) - regmap_write(bsp_priv->grf, reg, - RK3328_GMAC_RMII_CLK_25M | - RK3328_GMAC_SPEED_100M); + if (interface == PHY_INTERFACE_MODE_RMII && bsp_priv->integrated_phy) + reg = RK3328_GRF_MAC_CON2; else - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); + reg = RK3328_GRF_MAC_CON1; + + return rk_set_reg_speed(bsp_priv, &rk3328_reg_speed_data, reg, + interface, speed); } static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv) @@ -638,8 +611,7 @@ static void rk3328_integrated_phy_powerup(struct rk_priv_data *priv) static const struct rk_gmac_ops rk3328_ops = { .set_to_rgmii = rk3328_set_to_rgmii, .set_to_rmii = rk3328_set_to_rmii, - .set_rgmii_speed = rk3328_set_rgmii_speed, - .set_rmii_speed = rk3328_set_rmii_speed, + .set_speed = rk3328_set_speed, .integrated_phy_powerup = rk3328_integrated_phy_powerup, .integrated_phy_powerdown = rk_gmac_integrated_ephy_powerdown, }; @@ -648,19 +620,16 @@ static const struct rk_gmac_ops rk3328_ops = { #define RK3366_GRF_SOC_CON7 0x041c /* RK3366_GRF_SOC_CON6 */ -#define RK3366_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \ - GRF_CLR_BIT(11)) -#define RK3366_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \ - GRF_BIT(11)) +#define RK3366_GMAC_PHY_INTF_SEL(val) GRF_FIELD(11, 9, val) #define RK3366_GMAC_FLOW_CTRL GRF_BIT(8) #define RK3366_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8) #define RK3366_GMAC_SPEED_10M GRF_CLR_BIT(7) #define RK3366_GMAC_SPEED_100M GRF_BIT(7) #define RK3366_GMAC_RMII_CLK_25M GRF_BIT(3) #define RK3366_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3) -#define RK3366_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5)) -#define RK3366_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5)) -#define RK3366_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5)) +#define RK3366_GMAC_CLK_125M GRF_FIELD_CONST(5, 4, 0) +#define RK3366_GMAC_CLK_25M GRF_FIELD_CONST(5, 4, 3) +#define RK3366_GMAC_CLK_2_5M GRF_FIELD_CONST(5, 4, 2) #define RK3366_GMAC_RMII_MODE GRF_BIT(6) #define RK3366_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6) @@ -669,14 +638,14 @@ static const struct rk_gmac_ops rk3328_ops = { #define RK3366_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) #define RK3366_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) #define RK3366_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -#define RK3366_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RK3366_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3366_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RK3366_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_PHY_INTF_SEL_RGMII | + RK3366_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3366_GMAC_RMII_MODE_CLR); regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON7, DELAY_ENABLE(RK3366, tx_delay, rx_delay) | @@ -687,67 +656,45 @@ static void rk3366_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3366_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_PHY_INTF_SEL_RMII | RK3366_GMAC_RMII_MODE); + RK3366_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | + RK3366_GMAC_RMII_MODE); } -static void rk3366_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3366_reg_speed_data = { + .rgmii_10 = RK3366_GMAC_CLK_2_5M, + .rgmii_100 = RK3366_GMAC_CLK_25M, + .rgmii_1000 = RK3366_GMAC_CLK_125M, + .rmii_10 = RK3366_GMAC_RMII_CLK_2_5M | RK3366_GMAC_SPEED_10M, + .rmii_100 = RK3366_GMAC_RMII_CLK_25M | RK3366_GMAC_SPEED_100M, +}; -static void rk3366_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3366_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) { - regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_RMII_CLK_2_5M | - RK3366_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RK3366_GRF_SOC_CON6, - RK3366_GMAC_RMII_CLK_25M | - RK3366_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } + return rk_set_reg_speed(bsp_priv, &rk3366_reg_speed_data, + RK3366_GRF_SOC_CON6, interface, speed); } static const struct rk_gmac_ops rk3366_ops = { .set_to_rgmii = rk3366_set_to_rgmii, .set_to_rmii = rk3366_set_to_rmii, - .set_rgmii_speed = rk3366_set_rgmii_speed, - .set_rmii_speed = rk3366_set_rmii_speed, + .set_speed = rk3366_set_speed, }; #define RK3368_GRF_SOC_CON15 0x043c #define RK3368_GRF_SOC_CON16 0x0440 /* RK3368_GRF_SOC_CON15 */ -#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \ - GRF_CLR_BIT(11)) -#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \ - GRF_BIT(11)) +#define RK3368_GMAC_PHY_INTF_SEL(val) GRF_FIELD(11, 9, val) #define RK3368_GMAC_FLOW_CTRL GRF_BIT(8) #define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8) #define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7) #define RK3368_GMAC_SPEED_100M GRF_BIT(7) #define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3) #define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3) -#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5)) -#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5)) -#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5)) +#define RK3368_GMAC_CLK_125M GRF_FIELD_CONST(5, 4, 0) +#define RK3368_GMAC_CLK_25M GRF_FIELD_CONST(5, 4, 3) +#define RK3368_GMAC_CLK_2_5M GRF_FIELD_CONST(5, 4, 2) #define RK3368_GMAC_RMII_MODE GRF_BIT(6) #define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6) @@ -756,14 +703,14 @@ static const struct rk_gmac_ops rk3366_ops = { #define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) #define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) #define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3368_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RK3368_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_PHY_INTF_SEL_RGMII | + RK3368_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3368_GMAC_RMII_MODE_CLR); regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16, DELAY_ENABLE(RK3368, tx_delay, rx_delay) | @@ -774,67 +721,45 @@ static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE); + RK3368_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | + RK3368_GMAC_RMII_MODE); } -static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) - regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3368_reg_speed_data = { + .rgmii_10 = RK3368_GMAC_CLK_2_5M, + .rgmii_100 = RK3368_GMAC_CLK_25M, + .rgmii_1000 = RK3368_GMAC_CLK_125M, + .rmii_10 = RK3368_GMAC_RMII_CLK_2_5M | RK3368_GMAC_SPEED_10M, + .rmii_100 = RK3368_GMAC_RMII_CLK_25M | RK3368_GMAC_SPEED_100M, +}; -static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3368_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; - - if (speed == 10) { - regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_RMII_CLK_2_5M | - RK3368_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, - RK3368_GMAC_RMII_CLK_25M | - RK3368_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } + return rk_set_reg_speed(bsp_priv, &rk3368_reg_speed_data, + RK3368_GRF_SOC_CON15, interface, speed); } static const struct rk_gmac_ops rk3368_ops = { .set_to_rgmii = rk3368_set_to_rgmii, .set_to_rmii = rk3368_set_to_rmii, - .set_rgmii_speed = rk3368_set_rgmii_speed, - .set_rmii_speed = rk3368_set_rmii_speed, + .set_speed = rk3368_set_speed, }; #define RK3399_GRF_SOC_CON5 0xc214 #define RK3399_GRF_SOC_CON6 0xc218 /* RK3399_GRF_SOC_CON5 */ -#define RK3399_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \ - GRF_CLR_BIT(11)) -#define RK3399_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \ - GRF_BIT(11)) +#define RK3399_GMAC_PHY_INTF_SEL(val) GRF_FIELD(11, 9, val) #define RK3399_GMAC_FLOW_CTRL GRF_BIT(8) #define RK3399_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8) #define RK3399_GMAC_SPEED_10M GRF_CLR_BIT(7) #define RK3399_GMAC_SPEED_100M GRF_BIT(7) #define RK3399_GMAC_RMII_CLK_25M GRF_BIT(3) #define RK3399_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3) -#define RK3399_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5)) -#define RK3399_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5)) -#define RK3399_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5)) +#define RK3399_GMAC_CLK_125M GRF_FIELD_CONST(5, 4, 0) +#define RK3399_GMAC_CLK_25M GRF_FIELD_CONST(5, 4, 3) +#define RK3399_GMAC_CLK_2_5M GRF_FIELD_CONST(5, 4, 2) #define RK3399_GMAC_RMII_MODE GRF_BIT(6) #define RK3399_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6) @@ -843,14 +768,14 @@ static const struct rk_gmac_ops rk3368_ops = { #define RK3399_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) #define RK3399_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) #define RK3399_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) -#define RK3399_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RK3399_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3399_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RK3399_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_PHY_INTF_SEL_RGMII | + RK3399_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3399_GMAC_RMII_MODE_CLR); regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON6, DELAY_ENABLE(RK3399, tx_delay, rx_delay) | @@ -861,48 +786,92 @@ static void rk3399_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3399_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_PHY_INTF_SEL_RMII | RK3399_GMAC_RMII_MODE); + RK3399_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII) | + RK3399_GMAC_RMII_MODE); } -static void rk3399_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) +static const struct rk_reg_speed_data rk3399_reg_speed_data = { + .rgmii_10 = RK3399_GMAC_CLK_2_5M, + .rgmii_100 = RK3399_GMAC_CLK_25M, + .rgmii_1000 = RK3399_GMAC_CLK_125M, + .rmii_10 = RK3399_GMAC_RMII_CLK_2_5M | RK3399_GMAC_SPEED_10M, + .rmii_100 = RK3399_GMAC_RMII_CLK_25M | RK3399_GMAC_SPEED_100M, +}; + +static int rk3399_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; + return rk_set_reg_speed(bsp_priv, &rk3399_reg_speed_data, + RK3399_GRF_SOC_CON5, interface, speed); +} - if (speed == 10) - regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_CLK_2_5M); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_CLK_25M); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_CLK_125M); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); +static const struct rk_gmac_ops rk3399_ops = { + .set_to_rgmii = rk3399_set_to_rgmii, + .set_to_rmii = rk3399_set_to_rmii, + .set_speed = rk3399_set_speed, +}; + +#define RK3506_GRF_SOC_CON8 0x0020 +#define RK3506_GRF_SOC_CON11 0x002c + +#define RK3506_GMAC_RMII_MODE GRF_BIT(1) + +#define RK3506_GMAC_CLK_RMII_DIV2 GRF_BIT(3) +#define RK3506_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(3) + +#define RK3506_GMAC_CLK_SELECT_CRU GRF_CLR_BIT(5) +#define RK3506_GMAC_CLK_SELECT_IO GRF_BIT(5) + +#define RK3506_GMAC_CLK_RMII_GATE GRF_BIT(2) +#define RK3506_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(2) + +static void rk3506_set_to_rmii(struct rk_priv_data *bsp_priv) +{ + unsigned int id = bsp_priv->id, offset; + + offset = (id == 1) ? RK3506_GRF_SOC_CON11 : RK3506_GRF_SOC_CON8; + regmap_write(bsp_priv->grf, offset, RK3506_GMAC_RMII_MODE); } -static void rk3399_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static const struct rk_reg_speed_data rk3506_reg_speed_data = { + .rmii_10 = RK3506_GMAC_CLK_RMII_DIV20, + .rmii_100 = RK3506_GMAC_CLK_RMII_DIV2, +}; + +static int rk3506_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; + unsigned int id = bsp_priv->id, offset; - if (speed == 10) { - regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_RMII_CLK_2_5M | - RK3399_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RK3399_GRF_SOC_CON5, - RK3399_GMAC_RMII_CLK_25M | - RK3399_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } + offset = (id == 1) ? RK3506_GRF_SOC_CON11 : RK3506_GRF_SOC_CON8; + return rk_set_reg_speed(bsp_priv, &rk3506_reg_speed_data, + offset, interface, speed); } -static const struct rk_gmac_ops rk3399_ops = { - .set_to_rgmii = rk3399_set_to_rgmii, - .set_to_rmii = rk3399_set_to_rmii, - .set_rgmii_speed = rk3399_set_rgmii_speed, - .set_rmii_speed = rk3399_set_rmii_speed, +static void rk3506_set_clock_selection(struct rk_priv_data *bsp_priv, + bool input, bool enable) +{ + unsigned int value, offset, id = bsp_priv->id; + + offset = (id == 1) ? RK3506_GRF_SOC_CON11 : RK3506_GRF_SOC_CON8; + + value = input ? RK3506_GMAC_CLK_SELECT_IO : + RK3506_GMAC_CLK_SELECT_CRU; + value |= enable ? RK3506_GMAC_CLK_RMII_NOGATE : + RK3506_GMAC_CLK_RMII_GATE; + regmap_write(bsp_priv->grf, offset, value); +} + +static const struct rk_gmac_ops rk3506_ops = { + .set_to_rmii = rk3506_set_to_rmii, + .set_speed = rk3506_set_speed, + .set_clock_selection = rk3506_set_clock_selection, + .regs_valid = true, + .regs = { + 0xff4c8000, /* gmac0 */ + 0xff4d0000, /* gmac1 */ + 0x0, /* sentinel */ + }, }; #define RK3528_VO_GRF_GMAC_CON 0x0018 @@ -916,8 +885,8 @@ static const struct rk_gmac_ops rk3399_ops = { #define RK3528_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) #define RK3528_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) -#define RK3528_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) -#define RK3528_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) +#define RK3528_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(15, 8, val) +#define RK3528_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(7, 0, val) #define RK3528_GMAC0_PHY_INTF_SEL_RMII GRF_BIT(1) #define RK3528_GMAC1_PHY_INTF_SEL_RGMII GRF_CLR_BIT(8) @@ -931,9 +900,9 @@ static const struct rk_gmac_ops rk3399_ops = { #define RK3528_GMAC1_CLK_RMII_DIV2 GRF_BIT(10) #define RK3528_GMAC1_CLK_RMII_DIV20 GRF_CLR_BIT(10) -#define RK3528_GMAC1_CLK_RGMII_DIV1 (GRF_CLR_BIT(11) | GRF_CLR_BIT(10)) -#define RK3528_GMAC1_CLK_RGMII_DIV5 (GRF_BIT(11) | GRF_BIT(10)) -#define RK3528_GMAC1_CLK_RGMII_DIV50 (GRF_BIT(11) | GRF_CLR_BIT(10)) +#define RK3528_GMAC1_CLK_RGMII_DIV1 GRF_FIELD_CONST(11, 10, 0) +#define RK3528_GMAC1_CLK_RGMII_DIV5 GRF_FIELD_CONST(11, 10, 3) +#define RK3528_GMAC1_CLK_RGMII_DIV50 GRF_FIELD_CONST(11, 10, 2) #define RK3528_GMAC0_CLK_RMII_GATE GRF_BIT(2) #define RK3528_GMAC0_CLK_RMII_NOGATE GRF_CLR_BIT(2) @@ -965,43 +934,34 @@ static void rk3528_set_to_rmii(struct rk_priv_data *bsp_priv) RK3528_GMAC0_CLK_RMII_DIV2); } -static void rk3528_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; +static const struct rk_reg_speed_data rk3528_gmac0_reg_speed_data = { + .rmii_10 = RK3528_GMAC0_CLK_RMII_DIV20, + .rmii_100 = RK3528_GMAC0_CLK_RMII_DIV2, +}; - if (speed == 10) - regmap_write(bsp_priv->grf, RK3528_VPU_GRF_GMAC_CON5, - RK3528_GMAC1_CLK_RGMII_DIV50); - else if (speed == 100) - regmap_write(bsp_priv->grf, RK3528_VPU_GRF_GMAC_CON5, - RK3528_GMAC1_CLK_RGMII_DIV5); - else if (speed == 1000) - regmap_write(bsp_priv->grf, RK3528_VPU_GRF_GMAC_CON5, - RK3528_GMAC1_CLK_RGMII_DIV1); - else - dev_err(dev, "unknown speed value for RGMII! speed=%d", speed); -} +static const struct rk_reg_speed_data rk3528_gmac1_reg_speed_data = { + .rgmii_10 = RK3528_GMAC1_CLK_RGMII_DIV50, + .rgmii_100 = RK3528_GMAC1_CLK_RGMII_DIV5, + .rgmii_1000 = RK3528_GMAC1_CLK_RGMII_DIV1, + .rmii_10 = RK3528_GMAC1_CLK_RMII_DIV20, + .rmii_100 = RK3528_GMAC1_CLK_RMII_DIV2, +}; -static void rk3528_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3528_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; - unsigned int reg, val; + const struct rk_reg_speed_data *rsd; + unsigned int reg; - if (speed == 10) - val = bsp_priv->id == 1 ? RK3528_GMAC1_CLK_RMII_DIV20 : - RK3528_GMAC0_CLK_RMII_DIV20; - else if (speed == 100) - val = bsp_priv->id == 1 ? RK3528_GMAC1_CLK_RMII_DIV2 : - RK3528_GMAC0_CLK_RMII_DIV2; - else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - return; + if (bsp_priv->id == 1) { + rsd = &rk3528_gmac1_reg_speed_data; + reg = RK3528_VPU_GRF_GMAC_CON5; + } else { + rsd = &rk3528_gmac0_reg_speed_data; + reg = RK3528_VO_GRF_GMAC_CON; } - reg = bsp_priv->id == 1 ? RK3528_VPU_GRF_GMAC_CON5 : - RK3528_VO_GRF_GMAC_CON; - - regmap_write(bsp_priv->grf, reg, val); + return rk_set_reg_speed(bsp_priv, rsd, reg, interface, speed); } static void rk3528_set_clock_selection(struct rk_priv_data *bsp_priv, @@ -1035,8 +995,7 @@ static void rk3528_integrated_phy_powerdown(struct rk_priv_data *bsp_priv) static const struct rk_gmac_ops rk3528_ops = { .set_to_rgmii = rk3528_set_to_rgmii, .set_to_rmii = rk3528_set_to_rmii, - .set_rgmii_speed = rk3528_set_rgmii_speed, - .set_rmii_speed = rk3528_set_rmii_speed, + .set_speed = rk3528_set_speed, .set_clock_selection = rk3528_set_clock_selection, .integrated_phy_powerup = rk3528_integrated_phy_powerup, .integrated_phy_powerdown = rk3528_integrated_phy_powerdown, @@ -1054,10 +1013,7 @@ static const struct rk_gmac_ops rk3528_ops = { #define RK3568_GRF_GMAC1_CON1 0x038c /* RK3568_GRF_GMAC0_CON1 && RK3568_GRF_GMAC1_CON1 */ -#define RK3568_GMAC_PHY_INTF_SEL_RGMII \ - (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6)) -#define RK3568_GMAC_PHY_INTF_SEL_RMII \ - (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RK3568_GMAC_PHY_INTF_SEL(val) GRF_FIELD(6, 4, val) #define RK3568_GMAC_FLOW_CTRL GRF_BIT(3) #define RK3568_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3) #define RK3568_GMAC_RXCLK_DLY_ENABLE GRF_BIT(1) @@ -1066,8 +1022,8 @@ static const struct rk_gmac_ops rk3528_ops = { #define RK3568_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(0) /* RK3568_GRF_GMAC0_CON0 && RK3568_GRF_GMAC1_CON0 */ -#define RK3568_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RK3568_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3568_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RK3568_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) @@ -1084,7 +1040,7 @@ static void rk3568_set_to_rgmii(struct rk_priv_data *bsp_priv, RK3568_GMAC_CLK_TX_DL_CFG(tx_delay)); regmap_write(bsp_priv->grf, con1, - RK3568_GMAC_PHY_INTF_SEL_RGMII | + RK3568_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RK3568_GMAC_RXCLK_DLY_ENABLE | RK3568_GMAC_TXCLK_DLY_ENABLE); } @@ -1095,33 +1051,14 @@ static void rk3568_set_to_rmii(struct rk_priv_data *bsp_priv) con1 = (bsp_priv->id == 1) ? RK3568_GRF_GMAC1_CON1 : RK3568_GRF_GMAC0_CON1; - regmap_write(bsp_priv->grf, con1, RK3568_GMAC_PHY_INTF_SEL_RMII); -} - -static void rk3568_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk; - struct device *dev = &bsp_priv->pdev->dev; - long rate; - int ret; - - rate = rgmii_clock(speed); - if (rate < 0) { - dev_err(dev, "unknown speed value for GMAC speed=%d", speed); - return; - } - - ret = clk_set_rate(clk_mac_speed, rate); - if (ret) - dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n", - __func__, rate, ret); + regmap_write(bsp_priv->grf, con1, + RK3568_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII)); } static const struct rk_gmac_ops rk3568_ops = { .set_to_rgmii = rk3568_set_to_rgmii, .set_to_rmii = rk3568_set_to_rmii, - .set_rgmii_speed = rk3568_set_gmac_speed, - .set_rmii_speed = rk3568_set_gmac_speed, + .set_speed = rk_set_clk_mac_speed, .regs_valid = true, .regs = { 0xfe2a0000, /* gmac0 */ @@ -1141,8 +1078,8 @@ static const struct rk_gmac_ops rk3568_ops = { #define RK3576_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7) #define RK3576_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7) -#define RK3576_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RK3576_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RK3576_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RK3576_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) /* SDGMAC_GRF */ #define RK3576_GRF_GMAC_CON0 0X0020 @@ -1157,12 +1094,9 @@ static const struct rk_gmac_ops rk3568_ops = { #define RK3576_GMAC_CLK_RMII_DIV2 GRF_BIT(5) #define RK3576_GMAC_CLK_RMII_DIV20 GRF_CLR_BIT(5) -#define RK3576_GMAC_CLK_RGMII_DIV1 \ - (GRF_CLR_BIT(6) | GRF_CLR_BIT(5)) -#define RK3576_GMAC_CLK_RGMII_DIV5 \ - (GRF_BIT(6) | GRF_BIT(5)) -#define RK3576_GMAC_CLK_RGMII_DIV50 \ - (GRF_BIT(6) | GRF_CLR_BIT(5)) +#define RK3576_GMAC_CLK_RGMII_DIV1 GRF_FIELD_CONST(6, 5, 0) +#define RK3576_GMAC_CLK_RGMII_DIV5 GRF_FIELD_CONST(6, 5, 3) +#define RK3576_GMAC_CLK_RGMII_DIV50 GRF_FIELD_CONST(6, 5, 2) #define RK3576_GMAC_CLK_RMII_GATE GRF_BIT(4) #define RK3576_GMAC_CLK_RMII_NOGATE GRF_CLR_BIT(4) @@ -1205,42 +1139,24 @@ static void rk3576_set_to_rmii(struct rk_priv_data *bsp_priv) regmap_write(bsp_priv->grf, offset_con, RK3576_GMAC_RMII_MODE); } -static void rk3576_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; - unsigned int val = 0, offset_con; +static const struct rk_reg_speed_data rk3578_reg_speed_data = { + .rgmii_10 = RK3576_GMAC_CLK_RGMII_DIV50, + .rgmii_100 = RK3576_GMAC_CLK_RGMII_DIV5, + .rgmii_1000 = RK3576_GMAC_CLK_RGMII_DIV1, + .rmii_10 = RK3576_GMAC_CLK_RMII_DIV20, + .rmii_100 = RK3576_GMAC_CLK_RMII_DIV2, +}; - switch (speed) { - case 10: - if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) - val = RK3576_GMAC_CLK_RMII_DIV20; - else - val = RK3576_GMAC_CLK_RGMII_DIV50; - break; - case 100: - if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) - val = RK3576_GMAC_CLK_RMII_DIV2; - else - val = RK3576_GMAC_CLK_RGMII_DIV5; - break; - case 1000: - if (bsp_priv->phy_iface != PHY_INTERFACE_MODE_RMII) - val = RK3576_GMAC_CLK_RGMII_DIV1; - else - goto err; - break; - default: - goto err; - } +static int rk3576_set_gmac_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) +{ + unsigned int offset_con; offset_con = bsp_priv->id == 1 ? RK3576_GRF_GMAC_CON1 : RK3576_GRF_GMAC_CON0; - regmap_write(bsp_priv->grf, offset_con, val); - - return; -err: - dev_err(dev, "unknown speed value for GMAC speed=%d", speed); + return rk_set_reg_speed(bsp_priv, &rk3578_reg_speed_data, offset_con, + interface, speed); } static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input, @@ -1262,8 +1178,7 @@ static void rk3576_set_clock_selection(struct rk_priv_data *bsp_priv, bool input static const struct rk_gmac_ops rk3576_ops = { .set_to_rgmii = rk3576_set_to_rgmii, .set_to_rmii = rk3576_set_to_rmii, - .set_rgmii_speed = rk3576_set_gmac_speed, - .set_rmii_speed = rk3576_set_gmac_speed, + .set_speed = rk3576_set_gmac_speed, .set_clock_selection = rk3576_set_clock_selection, .php_grf_required = true, .regs_valid = true, @@ -1284,17 +1199,15 @@ static const struct rk_gmac_ops rk3576_ops = { #define RK3588_GMAC_TXCLK_DLY_ENABLE(id) GRF_BIT(2 * (id) + 2) #define RK3588_GMAC_TXCLK_DLY_DISABLE(id) GRF_CLR_BIT(2 * (id) + 2) -#define RK3588_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 8) -#define RK3588_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0xFF, 0) +#define RK3588_GMAC_CLK_RX_DL_CFG(val) GRF_FIELD(15, 8, val) +#define RK3588_GMAC_CLK_TX_DL_CFG(val) GRF_FIELD(7, 0, val) /* php_grf */ #define RK3588_GRF_GMAC_CON0 0X0008 #define RK3588_GRF_CLK_CON1 0X0070 -#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id) \ - (GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 + (id) * 6)) -#define RK3588_GMAC_PHY_INTF_SEL_RMII(id) \ - (GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 + (id) * 6)) +#define RK3588_GMAC_PHY_INTF_SEL(id, val) \ + (GRF_FIELD(5, 3, val) << ((id) * 6)) #define RK3588_GMAC_CLK_RMII_MODE(id) GRF_BIT(5 * (id)) #define RK3588_GMAC_CLK_RGMII_MODE(id) GRF_CLR_BIT(5 * (id)) @@ -1306,11 +1219,11 @@ static const struct rk_gmac_ops rk3576_ops = { #define RK3588_GMA_CLK_RMII_DIV20(id) GRF_CLR_BIT(5 * (id) + 2) #define RK3588_GMAC_CLK_RGMII_DIV1(id) \ - (GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3)) + (GRF_FIELD_CONST(3, 2, 0) << ((id) * 5)) #define RK3588_GMAC_CLK_RGMII_DIV5(id) \ - (GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) + (GRF_FIELD_CONST(3, 2, 3) << ((id) * 5)) #define RK3588_GMAC_CLK_RGMII_DIV50(id) \ - (GRF_CLR_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3)) + (GRF_FIELD_CONST(3, 2, 2) << ((id) * 5)) #define RK3588_GMAC_CLK_RMII_GATE(id) GRF_BIT(5 * (id) + 1) #define RK3588_GMAC_CLK_RMII_NOGATE(id) GRF_CLR_BIT(5 * (id) + 1) @@ -1324,7 +1237,7 @@ static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv, RK3588_GRF_GMAC_CON8; regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0, - RK3588_GMAC_PHY_INTF_SEL_RGMII(id)); + RK3588_GMAC_PHY_INTF_SEL(id, PHY_INTF_SEL_RGMII)); regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, RK3588_GMAC_CLK_RGMII_MODE(id)); @@ -1341,32 +1254,32 @@ static void rk3588_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rk3588_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->php_grf, RK3588_GRF_GMAC_CON0, - RK3588_GMAC_PHY_INTF_SEL_RMII(bsp_priv->id)); + RK3588_GMAC_PHY_INTF_SEL(bsp_priv->id, PHY_INTF_SEL_RMII)); regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, RK3588_GMAC_CLK_RMII_MODE(bsp_priv->id)); } -static void rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed) +static int rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) { - struct device *dev = &bsp_priv->pdev->dev; unsigned int val = 0, id = bsp_priv->id; switch (speed) { case 10: - if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + if (interface == PHY_INTERFACE_MODE_RMII) val = RK3588_GMA_CLK_RMII_DIV20(id); else val = RK3588_GMAC_CLK_RGMII_DIV50(id); break; case 100: - if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + if (interface == PHY_INTERFACE_MODE_RMII) val = RK3588_GMA_CLK_RMII_DIV2(id); else val = RK3588_GMAC_CLK_RGMII_DIV5(id); break; case 1000: - if (bsp_priv->phy_iface != PHY_INTERFACE_MODE_RMII) + if (interface != PHY_INTERFACE_MODE_RMII) val = RK3588_GMAC_CLK_RGMII_DIV1(id); else goto err; @@ -1377,9 +1290,9 @@ static void rk3588_set_gmac_speed(struct rk_priv_data *bsp_priv, int speed) regmap_write(bsp_priv->php_grf, RK3588_GRF_CLK_CON1, val); - return; + return 0; err: - dev_err(dev, "unknown speed value for GMAC speed=%d", speed); + return -EINVAL; } static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input, @@ -1397,8 +1310,7 @@ static void rk3588_set_clock_selection(struct rk_priv_data *bsp_priv, bool input static const struct rk_gmac_ops rk3588_ops = { .set_to_rgmii = rk3588_set_to_rgmii, .set_to_rmii = rk3588_set_to_rmii, - .set_rgmii_speed = rk3588_set_gmac_speed, - .set_rmii_speed = rk3588_set_gmac_speed, + .set_speed = rk3588_set_gmac_speed, .set_clock_selection = rk3588_set_clock_selection, .php_grf_required = true, .regs_valid = true, @@ -1412,8 +1324,7 @@ static const struct rk_gmac_ops rk3588_ops = { #define RV1108_GRF_GMAC_CON0 0X0900 /* RV1108_GRF_GMAC_CON0 */ -#define RV1108_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | \ - GRF_BIT(6)) +#define RV1108_GMAC_PHY_INTF_SEL(val) GRF_FIELD(6, 4, val) #define RV1108_GMAC_FLOW_CTRL GRF_BIT(3) #define RV1108_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(3) #define RV1108_GMAC_SPEED_10M GRF_CLR_BIT(2) @@ -1424,29 +1335,24 @@ static const struct rk_gmac_ops rk3588_ops = { static void rv1108_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0, - RV1108_GMAC_PHY_INTF_SEL_RMII); + RV1108_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII)); } -static void rv1108_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct device *dev = &bsp_priv->pdev->dev; +static const struct rk_reg_speed_data rv1108_reg_speed_data = { + .rmii_10 = RV1108_GMAC_RMII_CLK_2_5M | RV1108_GMAC_SPEED_10M, + .rmii_100 = RV1108_GMAC_RMII_CLK_25M | RV1108_GMAC_SPEED_100M, +}; - if (speed == 10) { - regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0, - RV1108_GMAC_RMII_CLK_2_5M | - RV1108_GMAC_SPEED_10M); - } else if (speed == 100) { - regmap_write(bsp_priv->grf, RV1108_GRF_GMAC_CON0, - RV1108_GMAC_RMII_CLK_25M | - RV1108_GMAC_SPEED_100M); - } else { - dev_err(dev, "unknown speed value for RMII! speed=%d", speed); - } +static int rv1108_set_speed(struct rk_priv_data *bsp_priv, + phy_interface_t interface, int speed) +{ + return rk_set_reg_speed(bsp_priv, &rv1108_reg_speed_data, + RV1108_GRF_GMAC_CON0, interface, speed); } static const struct rk_gmac_ops rv1108_ops = { .set_to_rmii = rv1108_set_to_rmii, - .set_rmii_speed = rv1108_set_rmii_speed, + .set_speed = rv1108_set_speed, }; #define RV1126_GRF_GMAC_CON0 0X0070 @@ -1454,10 +1360,7 @@ static const struct rk_gmac_ops rv1108_ops = { #define RV1126_GRF_GMAC_CON2 0X0078 /* RV1126_GRF_GMAC_CON0 */ -#define RV1126_GMAC_PHY_INTF_SEL_RGMII \ - (GRF_BIT(4) | GRF_CLR_BIT(5) | GRF_CLR_BIT(6)) -#define RV1126_GMAC_PHY_INTF_SEL_RMII \ - (GRF_CLR_BIT(4) | GRF_CLR_BIT(5) | GRF_BIT(6)) +#define RV1126_GMAC_PHY_INTF_SEL(val) GRF_FIELD(6, 4, val) #define RV1126_GMAC_FLOW_CTRL GRF_BIT(7) #define RV1126_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(7) #define RV1126_GMAC_M0_RXCLK_DLY_ENABLE GRF_BIT(1) @@ -1470,17 +1373,17 @@ static const struct rk_gmac_ops rv1108_ops = { #define RV1126_GMAC_M1_TXCLK_DLY_DISABLE GRF_CLR_BIT(2) /* RV1126_GRF_GMAC_CON1 */ -#define RV1126_GMAC_M0_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RV1126_GMAC_M0_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RV1126_GMAC_M0_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RV1126_GMAC_M0_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) /* RV1126_GRF_GMAC_CON2 */ -#define RV1126_GMAC_M1_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8) -#define RV1126_GMAC_M1_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) +#define RV1126_GMAC_M1_CLK_RX_DL_CFG(val) GRF_FIELD(14, 8, val) +#define RV1126_GMAC_M1_CLK_TX_DL_CFG(val) GRF_FIELD(6, 0, val) static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv, int tx_delay, int rx_delay) { regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0, - RV1126_GMAC_PHY_INTF_SEL_RGMII | + RV1126_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RGMII) | RV1126_GMAC_M0_RXCLK_DLY_ENABLE | RV1126_GMAC_M0_TXCLK_DLY_ENABLE | RV1126_GMAC_M1_RXCLK_DLY_ENABLE | @@ -1498,65 +1401,20 @@ static void rv1126_set_to_rgmii(struct rk_priv_data *bsp_priv, static void rv1126_set_to_rmii(struct rk_priv_data *bsp_priv) { regmap_write(bsp_priv->grf, RV1126_GRF_GMAC_CON0, - RV1126_GMAC_PHY_INTF_SEL_RMII); -} - -static void rv1126_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk; - struct device *dev = &bsp_priv->pdev->dev; - long rate; - int ret; - - rate = rgmii_clock(speed); - if (rate < 0) { - dev_err(dev, "unknown speed value for RGMII speed=%d", speed); - return; - } - - ret = clk_set_rate(clk_mac_speed, rate); - if (ret) - dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n", - __func__, rate, ret); -} - -static void rv1126_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) -{ - struct clk *clk_mac_speed = bsp_priv->clks[RK_CLK_MAC_SPEED].clk; - struct device *dev = &bsp_priv->pdev->dev; - unsigned long rate; - int ret; - - switch (speed) { - case 10: - rate = 2500000; - break; - case 100: - rate = 25000000; - break; - default: - dev_err(dev, "unknown speed value for RGMII speed=%d", speed); - return; - } - - ret = clk_set_rate(clk_mac_speed, rate); - if (ret) - dev_err(dev, "%s: set clk_mac_speed rate %ld failed %d\n", - __func__, rate, ret); + RV1126_GMAC_PHY_INTF_SEL(PHY_INTF_SEL_RMII)); } static const struct rk_gmac_ops rv1126_ops = { .set_to_rgmii = rv1126_set_to_rgmii, .set_to_rmii = rv1126_set_to_rmii, - .set_rgmii_speed = rv1126_set_rgmii_speed, - .set_rmii_speed = rv1126_set_rmii_speed, + .set_speed = rk_set_clk_mac_speed, }; static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat) { struct rk_priv_data *bsp_priv = plat->bsp_priv; - struct device *dev = &bsp_priv->pdev->dev; int phy_iface = bsp_priv->phy_iface; + struct device *dev = bsp_priv->dev; int i, j, ret; bsp_priv->clk_enabled = false; @@ -1583,16 +1441,10 @@ static int rk_gmac_clk_init(struct plat_stmmacenet_data *plat) if (ret) return dev_err_probe(dev, ret, "Failed to get clocks\n"); - /* "stmmaceth" will be enabled by the core */ - bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth"); - ret = PTR_ERR_OR_ZERO(bsp_priv->clk_mac); - if (ret) - return dev_err_probe(dev, ret, "Cannot get stmmaceth clock\n"); - if (bsp_priv->clock_input) { dev_info(dev, "clock input from PHY\n"); } else if (phy_iface == PHY_INTERFACE_MODE_RMII) { - clk_set_rate(bsp_priv->clk_mac, 50000000); + clk_set_rate(plat->stmmac_clk, 50000000); } if (plat->phy_node && bsp_priv->integrated_phy) { @@ -1630,14 +1482,15 @@ static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) } } else { if (bsp_priv->clk_enabled) { + if (bsp_priv->ops && bsp_priv->ops->set_clock_selection) { + bsp_priv->ops->set_clock_selection(bsp_priv, + bsp_priv->clock_input, false); + } + clk_bulk_disable_unprepare(bsp_priv->num_clks, bsp_priv->clks); clk_disable_unprepare(bsp_priv->clk_phy); - if (bsp_priv->ops && bsp_priv->ops->set_clock_selection) - bsp_priv->ops->set_clock_selection(bsp_priv, - bsp_priv->clock_input, false); - bsp_priv->clk_enabled = false; } } @@ -1648,8 +1501,8 @@ static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) { struct regulator *ldo = bsp_priv->regulator; + struct device *dev = bsp_priv->dev; int ret; - struct device *dev = &bsp_priv->pdev->dev; if (enable) { ret = regulator_enable(ldo); @@ -1773,7 +1626,7 @@ static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev, dev_info(dev, "integrated PHY? (%s).\n", bsp_priv->integrated_phy ? "yes" : "no"); - bsp_priv->pdev = pdev; + bsp_priv->dev = dev; return bsp_priv; } @@ -1793,7 +1646,7 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv) return -EINVAL; break; default: - dev_err(&bsp_priv->pdev->dev, + dev_err(bsp_priv->dev, "unsupported interface %d", bsp_priv->phy_iface); } return 0; @@ -1801,8 +1654,8 @@ static int rk_gmac_check_ops(struct rk_priv_data *bsp_priv) static int rk_gmac_powerup(struct rk_priv_data *bsp_priv) { + struct device *dev = bsp_priv->dev; int ret; - struct device *dev = &bsp_priv->pdev->dev; ret = rk_gmac_check_ops(bsp_priv); if (ret) @@ -1858,37 +1711,73 @@ static void rk_gmac_powerdown(struct rk_priv_data *gmac) if (gmac->integrated_phy && gmac->ops->integrated_phy_powerdown) gmac->ops->integrated_phy_powerdown(gmac); - pm_runtime_put_sync(&gmac->pdev->dev); + pm_runtime_put_sync(gmac->dev); phy_power_on(gmac, false); gmac_clk_enable(gmac, false); } +static void rk_get_interfaces(struct stmmac_priv *priv, void *bsp_priv, + unsigned long *interfaces) +{ + struct rk_priv_data *rk = bsp_priv; + + if (rk->ops->set_to_rgmii) + phy_interface_set_rgmii(interfaces); + + if (rk->ops->set_to_rmii) + __set_bit(PHY_INTERFACE_MODE_RMII, interfaces); +} + static int rk_set_clk_tx_rate(void *bsp_priv_, struct clk *clk_tx_i, phy_interface_t interface, int speed) { struct rk_priv_data *bsp_priv = bsp_priv_; - struct device *dev = &bsp_priv->pdev->dev; - switch (bsp_priv->phy_iface) { - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - if (bsp_priv->ops->set_rgmii_speed) - bsp_priv->ops->set_rgmii_speed(bsp_priv, speed); - break; - case PHY_INTERFACE_MODE_RMII: - if (bsp_priv->ops->set_rmii_speed) - bsp_priv->ops->set_rmii_speed(bsp_priv, speed); - break; - default: - dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); - } + if (bsp_priv->ops->set_speed) + return bsp_priv->ops->set_speed(bsp_priv, interface, speed); + + return -EINVAL; +} + +static int rk_gmac_suspend(struct device *dev, void *bsp_priv_) +{ + struct rk_priv_data *bsp_priv = bsp_priv_; + + /* Keep the PHY up if we use Wake-on-Lan. */ + if (!device_may_wakeup(dev)) + rk_gmac_powerdown(bsp_priv); return 0; } +static int rk_gmac_resume(struct device *dev, void *bsp_priv_) +{ + struct rk_priv_data *bsp_priv = bsp_priv_; + + /* The PHY was up for Wake-on-Lan. */ + if (!device_may_wakeup(dev)) + rk_gmac_powerup(bsp_priv); + + return 0; +} + +static int rk_gmac_init(struct device *dev, void *bsp_priv) +{ + return rk_gmac_powerup(bsp_priv); +} + +static void rk_gmac_exit(struct device *dev, void *bsp_priv_) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + struct rk_priv_data *bsp_priv = bsp_priv_; + + rk_gmac_powerdown(bsp_priv); + + if (priv->plat->phy_node && bsp_priv->integrated_phy) + clk_put(bsp_priv->clk_phy); +} + static int rk_gmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -1913,13 +1802,18 @@ static int rk_gmac_probe(struct platform_device *pdev) /* If the stmmac is not already selected as gmac4, * then make sure we fallback to gmac. */ - if (!plat_dat->has_gmac4) { - plat_dat->has_gmac = true; + if (plat_dat->core_type != DWMAC_CORE_GMAC4) { + plat_dat->core_type = DWMAC_CORE_GMAC; plat_dat->rx_fifo_size = 4096; plat_dat->tx_fifo_size = 2048; } + plat_dat->get_interfaces = rk_get_interfaces; plat_dat->set_clk_tx_rate = rk_set_clk_tx_rate; + plat_dat->init = rk_gmac_init; + plat_dat->exit = rk_gmac_exit; + plat_dat->suspend = rk_gmac_suspend; + plat_dat->resume = rk_gmac_resume; plat_dat->bsp_priv = rk_gmac_setup(pdev, plat_dat, data); if (IS_ERR(plat_dat->bsp_priv)) @@ -1929,62 +1823,9 @@ static int rk_gmac_probe(struct platform_device *pdev) if (ret) return ret; - ret = rk_gmac_powerup(plat_dat->bsp_priv); - if (ret) - return ret; - - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - if (ret) - goto err_gmac_powerdown; - - return 0; - -err_gmac_powerdown: - rk_gmac_powerdown(plat_dat->bsp_priv); - - return ret; + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } -static void rk_gmac_remove(struct platform_device *pdev) -{ - struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(&pdev->dev); - - stmmac_dvr_remove(&pdev->dev); - - rk_gmac_powerdown(bsp_priv); -} - -#ifdef CONFIG_PM_SLEEP -static int rk_gmac_suspend(struct device *dev) -{ - struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev); - int ret = stmmac_suspend(dev); - - /* Keep the PHY up if we use Wake-on-Lan. */ - if (!device_may_wakeup(dev)) { - rk_gmac_powerdown(bsp_priv); - bsp_priv->suspended = true; - } - - return ret; -} - -static int rk_gmac_resume(struct device *dev) -{ - struct rk_priv_data *bsp_priv = get_stmmac_bsp_priv(dev); - - /* The PHY was up for Wake-on-Lan. */ - if (bsp_priv->suspended) { - rk_gmac_powerup(bsp_priv); - bsp_priv->suspended = false; - } - - return stmmac_resume(dev); -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(rk_gmac_pm_ops, rk_gmac_suspend, rk_gmac_resume); - static const struct of_device_id rk_gmac_dwmac_match[] = { { .compatible = "rockchip,px30-gmac", .data = &px30_ops }, { .compatible = "rockchip,rk3128-gmac", .data = &rk3128_ops }, @@ -1995,6 +1836,7 @@ static const struct of_device_id rk_gmac_dwmac_match[] = { { .compatible = "rockchip,rk3366-gmac", .data = &rk3366_ops }, { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops }, { .compatible = "rockchip,rk3399-gmac", .data = &rk3399_ops }, + { .compatible = "rockchip,rk3506-gmac", .data = &rk3506_ops }, { .compatible = "rockchip,rk3528-gmac", .data = &rk3528_ops }, { .compatible = "rockchip,rk3568-gmac", .data = &rk3568_ops }, { .compatible = "rockchip,rk3576-gmac", .data = &rk3576_ops }, @@ -2007,10 +1849,9 @@ MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); static struct platform_driver rk_gmac_dwmac_driver = { .probe = rk_gmac_probe, - .remove = rk_gmac_remove, .driver = { .name = "rk_gmac-dwmac", - .pm = &rk_gmac_pm_ops, + .pm = &stmmac_simple_pm_ops, .of_match_table = rk_gmac_dwmac_match, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c index 221539d760bc..5a485ee98fa7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-s32.c @@ -24,10 +24,10 @@ #define GMAC_INTF_RATE_125M 125000000 /* 125MHz */ /* SoC PHY interface control register */ -#define PHY_INTF_SEL_MII 0x00 -#define PHY_INTF_SEL_SGMII 0x01 -#define PHY_INTF_SEL_RGMII 0x02 -#define PHY_INTF_SEL_RMII 0x08 +#define S32_PHY_INTF_SEL_MII 0x00 +#define S32_PHY_INTF_SEL_SGMII 0x01 +#define S32_PHY_INTF_SEL_RGMII 0x02 +#define S32_PHY_INTF_SEL_RMII 0x08 struct s32_priv_data { void __iomem *ioaddr; @@ -40,14 +40,14 @@ struct s32_priv_data { static int s32_gmac_write_phy_intf_select(struct s32_priv_data *gmac) { - writel(PHY_INTF_SEL_RGMII, gmac->ctrl_sts); + writel(S32_PHY_INTF_SEL_RGMII, gmac->ctrl_sts); dev_dbg(gmac->dev, "PHY mode set to %s\n", phy_modes(*gmac->intf_mode)); return 0; } -static int s32_gmac_init(struct platform_device *pdev, void *priv) +static int s32_gmac_init(struct device *dev, void *priv) { struct s32_priv_data *gmac = priv; int ret; @@ -55,31 +55,31 @@ static int s32_gmac_init(struct platform_device *pdev, void *priv) /* Set initial TX interface clock */ ret = clk_prepare_enable(gmac->tx_clk); if (ret) { - dev_err(&pdev->dev, "Can't enable tx clock\n"); + dev_err(dev, "Can't enable tx clock\n"); return ret; } ret = clk_set_rate(gmac->tx_clk, GMAC_INTF_RATE_125M); if (ret) { - dev_err(&pdev->dev, "Can't set tx clock\n"); + dev_err(dev, "Can't set tx clock\n"); goto err_tx_disable; } /* Set initial RX interface clock */ ret = clk_prepare_enable(gmac->rx_clk); if (ret) { - dev_err(&pdev->dev, "Can't enable rx clock\n"); + dev_err(dev, "Can't enable rx clock\n"); goto err_tx_disable; } ret = clk_set_rate(gmac->rx_clk, GMAC_INTF_RATE_125M); if (ret) { - dev_err(&pdev->dev, "Can't set rx clock\n"); + dev_err(dev, "Can't set rx clock\n"); goto err_txrx_disable; } /* Set interface mode */ ret = s32_gmac_write_phy_intf_select(gmac); if (ret) { - dev_err(&pdev->dev, "Can't set PHY interface mode\n"); + dev_err(dev, "Can't set PHY interface mode\n"); goto err_txrx_disable; } @@ -92,7 +92,7 @@ err_tx_disable: return ret; } -static void s32_gmac_exit(struct platform_device *pdev, void *priv) +static void s32_gmac_exit(struct device *dev, void *priv) { struct s32_priv_data *gmac = priv; @@ -146,7 +146,7 @@ static int s32_dwmac_probe(struct platform_device *pdev) gmac->ioaddr = res.addr; /* S32CC core feature set */ - plat->has_gmac4 = true; + plat->core_type = DWMAC_CORE_GMAC4; plat->pmt = 1; plat->flags |= STMMAC_FLAG_SPH_DISABLE; plat->rx_fifo_size = 20480; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 116855658559..a2b52d2c4eb6 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -5,6 +5,7 @@ */ #include <linux/mfd/altera-sysmgr.h> +#include <linux/clocksource_ids.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_net.h> @@ -15,8 +16,10 @@ #include <linux/reset.h> #include <linux/stmmac.h> +#include "dwxgmac2.h" #include "stmmac.h" #include "stmmac_platform.h" +#include "stmmac_ptp.h" #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII 0x0 #define SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII 0x1 @@ -41,15 +44,24 @@ #define SGMII_ADAPTER_ENABLE 0x0000 #define SGMII_ADAPTER_DISABLE 0x0001 +#define SMTG_MDIO_ADDR 0x15 +#define SMTG_TSC_WORD0 0xC +#define SMTG_TSC_WORD1 0xD +#define SMTG_TSC_WORD2 0xE +#define SMTG_TSC_WORD3 0xF +#define SMTG_TSC_SHIFT 16 + struct socfpga_dwmac; struct socfpga_dwmac_ops { int (*set_phy_mode)(struct socfpga_dwmac *dwmac_priv); + void (*setup_plat_dat)(struct socfpga_dwmac *dwmac_priv); }; struct socfpga_dwmac { u32 reg_offset; u32 reg_shift; struct device *dev; + struct plat_stmmacenet_data *plat_dat; struct regmap *sys_mgr_base_addr; struct reset_control *stmmac_rst; struct reset_control *stmmac_ocp_rst; @@ -58,17 +70,15 @@ struct socfpga_dwmac { void __iomem *sgmii_adapter_base; bool f2h_ptp_ref_clk; const struct socfpga_dwmac_ops *ops; - struct mdio_device *pcs_mdiodev; }; -static void socfpga_dwmac_fix_mac_speed(void *priv, int speed, unsigned int mode) +static void socfpga_dwmac_fix_mac_speed(void *bsp_priv, int speed, + unsigned int mode) { - struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; + struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)bsp_priv; + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dwmac->dev)); void __iomem *splitter_base = dwmac->splitter_base; void __iomem *sgmii_adapter_base = dwmac->sgmii_adapter_base; - struct device *dev = dwmac->dev; - struct net_device *ndev = dev_get_drvdata(dev); - struct phy_device *phy_dev = ndev->phydev; u32 val; if (sgmii_adapter_base) @@ -95,7 +105,9 @@ static void socfpga_dwmac_fix_mac_speed(void *priv, int speed, unsigned int mode writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); } - if (phy_dev && sgmii_adapter_base) + if ((priv->plat->phy_interface == PHY_INTERFACE_MODE_SGMII || + priv->plat->phy_interface == PHY_INTERFACE_MODE_1000BASEX) && + sgmii_adapter_base) writew(SGMII_ADAPTER_ENABLE, sgmii_adapter_base + SGMII_ADAPTER_CTRL_REG); } @@ -233,10 +245,7 @@ err_node_put: static int socfpga_get_plat_phymode(struct socfpga_dwmac *dwmac) { - struct net_device *ndev = dev_get_drvdata(dwmac->dev); - struct stmmac_priv *priv = netdev_priv(ndev); - - return priv->plat->mac_interface; + return dwmac->plat_dat->phy_interface; } static void socfpga_sgmii_config(struct socfpga_dwmac *dwmac, bool enable) @@ -258,6 +267,7 @@ static int socfpga_set_phy_mode_common(int phymode, u32 *val) case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII: case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_1000BASEX: *val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; break; case PHY_INTERFACE_MODE_RMII: @@ -269,6 +279,112 @@ static int socfpga_set_phy_mode_common(int phymode, u32 *val) return 0; } +static void get_smtgtime(struct mii_bus *mii, int smtg_addr, u64 *smtg_time) +{ + u64 ns; + + ns = mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD3); + ns <<= SMTG_TSC_SHIFT; + ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD2); + ns <<= SMTG_TSC_SHIFT; + ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD1); + ns <<= SMTG_TSC_SHIFT; + ns |= mdiobus_read(mii, smtg_addr, SMTG_TSC_WORD0); + + *smtg_time = ns; +} + +static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system, + void *ctx) +{ + struct stmmac_priv *priv = (struct stmmac_priv *)ctx; + u32 num_snapshot, gpio_value, acr_value; + void __iomem *ptpaddr = priv->ptpaddr; + void __iomem *ioaddr = priv->hw->pcsr; + unsigned long flags; + u64 smtg_time = 0; + u64 ptp_time = 0; + int i, ret; + u32 v; + + /* Both internal crosstimestamping and external triggered event + * timestamping cannot be run concurrently. + */ + if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN) + return -EBUSY; + + mutex_lock(&priv->aux_ts_lock); + /* Enable Internal snapshot trigger */ + acr_value = readl(ptpaddr + PTP_ACR); + acr_value &= ~PTP_ACR_MASK; + switch (priv->plat->int_snapshot_num) { + case AUX_SNAPSHOT0: + acr_value |= PTP_ACR_ATSEN0; + break; + case AUX_SNAPSHOT1: + acr_value |= PTP_ACR_ATSEN1; + break; + case AUX_SNAPSHOT2: + acr_value |= PTP_ACR_ATSEN2; + break; + case AUX_SNAPSHOT3: + acr_value |= PTP_ACR_ATSEN3; + break; + default: + mutex_unlock(&priv->aux_ts_lock); + return -EINVAL; + } + writel(acr_value, ptpaddr + PTP_ACR); + + /* Clear FIFO */ + acr_value = readl(ptpaddr + PTP_ACR); + acr_value |= PTP_ACR_ATSFC; + writel(acr_value, ptpaddr + PTP_ACR); + /* Release the mutex */ + mutex_unlock(&priv->aux_ts_lock); + + /* Trigger Internal snapshot signal. Create a rising edge by just toggle + * the GPO0 to low and back to high. + */ + gpio_value = readl(ioaddr + XGMAC_GPIO_STATUS); + gpio_value &= ~XGMAC_GPIO_GPO0; + writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); + gpio_value |= XGMAC_GPIO_GPO0; + writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); + + /* Poll for time sync operation done */ + ret = readl_poll_timeout(priv->ioaddr + XGMAC_INT_STATUS, v, + (v & XGMAC_INT_TSIS), 100, 10000); + if (ret) { + netdev_err(priv->dev, "%s: Wait for time sync operation timeout\n", + __func__); + return ret; + } + + *system = (struct system_counterval_t) { + .cycles = 0, + .cs_id = CSID_ARM_ARCH_COUNTER, + .use_nsecs = false, + }; + + num_snapshot = (readl(ioaddr + XGMAC_TIMESTAMP_STATUS) & + XGMAC_TIMESTAMP_ATSNS_MASK) >> + XGMAC_TIMESTAMP_ATSNS_SHIFT; + + /* Repeat until the timestamps are from the FIFO last segment */ + for (i = 0; i < num_snapshot; i++) { + read_lock_irqsave(&priv->ptp_lock, flags); + stmmac_get_ptptime(priv, ptpaddr, &ptp_time); + *device = ns_to_ktime(ptp_time); + read_unlock_irqrestore(&priv->ptp_lock, flags); + } + + get_smtgtime(priv->mii, SMTG_MDIO_ADDR, &smtg_time); + system->cycles = smtg_time; + + return 0; +} + static int socfpga_gen5_set_phy_mode(struct socfpga_dwmac *dwmac) { struct regmap *sys_mgr_base_addr = dwmac->sys_mgr_base_addr; @@ -435,6 +551,50 @@ static struct phylink_pcs *socfpga_dwmac_select_pcs(struct stmmac_priv *priv, return priv->hw->phylink_pcs; } +static int socfpga_dwmac_init(struct device *dev, void *bsp_priv) +{ + struct socfpga_dwmac *dwmac = bsp_priv; + + return dwmac->ops->set_phy_mode(dwmac); +} + +static void socfpga_gen5_setup_plat_dat(struct socfpga_dwmac *dwmac) +{ + struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat; + + plat_dat->core_type = DWMAC_CORE_GMAC; + + /* Rx watchdog timer in dwmac is buggy in this hw */ + plat_dat->riwt_off = 1; +} + +static void socfpga_agilex5_setup_plat_dat(struct socfpga_dwmac *dwmac) +{ + struct plat_stmmacenet_data *plat_dat = dwmac->plat_dat; + + plat_dat->core_type = DWMAC_CORE_XGMAC; + + /* Enable TSO */ + plat_dat->flags |= STMMAC_FLAG_TSO_EN; + + /* Enable TBS */ + switch (plat_dat->tx_queues_to_use) { + case 8: + plat_dat->tx_queues_cfg[7].tbs_en = true; + fallthrough; + case 7: + plat_dat->tx_queues_cfg[6].tbs_en = true; + break; + default: + /* Tx Queues 0 - 5 doesn't support TBS on Agilex5 */ + break; + } + + /* Hw supported cross-timestamp */ + plat_dat->int_snapshot_num = AUX_SNAPSHOT0; + plat_dat->crosststamp = smtg_crosststamp; +} + static int socfpga_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -442,8 +602,6 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret; struct socfpga_dwmac *dwmac; - struct net_device *ndev; - struct stmmac_priv *stpriv; const struct socfpga_dwmac_ops *ops; ops = device_get_match_data(&pdev->dev); @@ -479,98 +637,54 @@ static int socfpga_dwmac_probe(struct platform_device *pdev) return ret; } + /* The socfpga driver needs to control the stmmac reset to set the phy + * mode. Create a copy of the core reset handle so it can be used by + * the driver later. + */ + dwmac->stmmac_rst = plat_dat->stmmac_rst; dwmac->ops = ops; + dwmac->plat_dat = plat_dat; + plat_dat->bsp_priv = dwmac; plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; + plat_dat->init = socfpga_dwmac_init; plat_dat->pcs_init = socfpga_dwmac_pcs_init; plat_dat->pcs_exit = socfpga_dwmac_pcs_exit; plat_dat->select_pcs = socfpga_dwmac_select_pcs; - plat_dat->has_gmac = true; - - plat_dat->riwt_off = 1; - - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - if (ret) - return ret; - - ndev = platform_get_drvdata(pdev); - stpriv = netdev_priv(ndev); - - /* The socfpga driver needs to control the stmmac reset to set the phy - * mode. Create a copy of the core reset handle so it can be used by - * the driver later. - */ - dwmac->stmmac_rst = stpriv->plat->stmmac_rst; - ret = ops->set_phy_mode(dwmac); - if (ret) - goto err_dvr_remove; + ops->setup_plat_dat(dwmac); - return 0; - -err_dvr_remove: - stmmac_dvr_remove(&pdev->dev); - - return ret; -} - -#ifdef CONFIG_PM_SLEEP -static int socfpga_dwmac_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct socfpga_dwmac *dwmac_priv = get_stmmac_bsp_priv(dev); - - dwmac_priv->ops->set_phy_mode(priv->plat->bsp_priv); - - return stmmac_resume(dev); + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } -#endif /* CONFIG_PM_SLEEP */ - -static int __maybe_unused socfpga_dwmac_runtime_suspend(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - - stmmac_bus_clks_config(priv, false); - - return 0; -} - -static int __maybe_unused socfpga_dwmac_runtime_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - - return stmmac_bus_clks_config(priv, true); -} - -static const struct dev_pm_ops socfpga_dwmac_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stmmac_suspend, socfpga_dwmac_resume) - SET_RUNTIME_PM_OPS(socfpga_dwmac_runtime_suspend, socfpga_dwmac_runtime_resume, NULL) -}; static const struct socfpga_dwmac_ops socfpga_gen5_ops = { .set_phy_mode = socfpga_gen5_set_phy_mode, + .setup_plat_dat = socfpga_gen5_setup_plat_dat, }; static const struct socfpga_dwmac_ops socfpga_gen10_ops = { .set_phy_mode = socfpga_gen10_set_phy_mode, + .setup_plat_dat = socfpga_gen5_setup_plat_dat, +}; + +static const struct socfpga_dwmac_ops socfpga_agilex5_ops = { + .set_phy_mode = socfpga_gen10_set_phy_mode, + .setup_plat_dat = socfpga_agilex5_setup_plat_dat, }; static const struct of_device_id socfpga_dwmac_match[] = { { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gen5_ops }, { .compatible = "altr,socfpga-stmmac-a10-s10", .data = &socfpga_gen10_ops }, + { .compatible = "altr,socfpga-stmmac-agilex5", .data = &socfpga_agilex5_ops }, { } }; MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); static struct platform_driver socfpga_dwmac_driver = { .probe = socfpga_dwmac_probe, - .remove = stmmac_pltfr_remove, .driver = { .name = "socfpga-dwmac", - .pm = &socfpga_dwmac_pm_ops, + .pm = &stmmac_pltfr_pm_ops, .of_match_table = socfpga_dwmac_match, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c index 3303784cbbf8..44d4ceb8415f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sophgo.c @@ -7,11 +7,16 @@ #include <linux/clk.h> #include <linux/module.h> +#include <linux/property.h> #include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include "stmmac_platform.h" +struct sophgo_dwmac_data { + bool has_internal_rx_delay; +}; + static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat, struct stmmac_resources *stmmac_res) @@ -24,7 +29,6 @@ static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE; plat_dat->set_clk_tx_rate = stmmac_set_clk_tx_rate; plat_dat->multicast_filter_bins = 0; - plat_dat->unicast_filter_entries = 1; return 0; } @@ -32,6 +36,7 @@ static int sophgo_sg2044_dwmac_init(struct platform_device *pdev, static int sophgo_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; + const struct sophgo_dwmac_data *data; struct stmmac_resources stmmac_res; struct device *dev = &pdev->dev; int ret; @@ -50,10 +55,23 @@ static int sophgo_dwmac_probe(struct platform_device *pdev) if (ret) return ret; + data = device_get_match_data(&pdev->dev); + if (data && data->has_internal_rx_delay) { + plat_dat->phy_interface = phy_fix_phy_mode_for_mac_delays(plat_dat->phy_interface, + false, true); + if (plat_dat->phy_interface == PHY_INTERFACE_MODE_NA) + return -EINVAL; + } + return stmmac_dvr_probe(dev, plat_dat, &stmmac_res); } +static const struct sophgo_dwmac_data sg2042_dwmac_data = { + .has_internal_rx_delay = true, +}; + static const struct of_device_id sophgo_dwmac_match[] = { + { .compatible = "sophgo,sg2042-dwmac", .data = &sg2042_dwmac_data }, { .compatible = "sophgo,sg2044-dwmac" }, { /* sentinel */ } }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c index 2013d7477eb7..16b955a6d77b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-starfive.c @@ -15,8 +15,6 @@ #include "stmmac_platform.h" -#define STARFIVE_DWMAC_PHY_INFT_RGMII 0x1 -#define STARFIVE_DWMAC_PHY_INFT_RMII 0x4 #define STARFIVE_DWMAC_PHY_INFT_FIELD 0x7U #define JH7100_SYSMAIN_REGISTER49_DLYCHAIN 0xc8 @@ -35,25 +33,15 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) struct starfive_dwmac *dwmac = plat_dat->bsp_priv; struct regmap *regmap; unsigned int args[2]; - unsigned int mode; + int phy_intf_sel; int err; - switch (plat_dat->mac_interface) { - case PHY_INTERFACE_MODE_RMII: - mode = STARFIVE_DWMAC_PHY_INFT_RMII; - break; - - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - mode = STARFIVE_DWMAC_PHY_INFT_RGMII; - break; - - default: - dev_err(dwmac->dev, "unsupported interface %d\n", - plat_dat->mac_interface); - return -EINVAL; + phy_intf_sel = stmmac_get_phy_intf_sel(plat_dat->phy_interface); + if (phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) { + dev_err(dwmac->dev, "unsupported interface %s\n", + phy_modes(plat_dat->phy_interface)); + return phy_intf_sel < 0 ? phy_intf_sel : -EINVAL; } regmap = syscon_regmap_lookup_by_phandle_args(dwmac->dev->of_node, @@ -65,7 +53,7 @@ static int starfive_dwmac_set_mode(struct plat_stmmacenet_data *plat_dat) /* args[0]:offset args[1]: shift */ err = regmap_update_bits(regmap, args[0], STARFIVE_DWMAC_PHY_INFT_FIELD << args[1], - mode << args[1]); + phy_intf_sel << args[1]); if (err) return dev_err_probe(dwmac->dev, err, "error setting phy mode\n"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index be57c6c12c1c..f50547b67fbc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -23,12 +23,7 @@ #define DWMAC_50MHZ 50000000 -#define IS_PHY_IF_MODE_RGMII(iface) (iface == PHY_INTERFACE_MODE_RGMII || \ - iface == PHY_INTERFACE_MODE_RGMII_ID || \ - iface == PHY_INTERFACE_MODE_RGMII_RXID || \ - iface == PHY_INTERFACE_MODE_RGMII_TXID) - -#define IS_PHY_IF_MODE_GBIT(iface) (IS_PHY_IF_MODE_RGMII(iface) || \ +#define IS_PHY_IF_MODE_GBIT(iface) (phy_interface_mode_is_rgmii(iface) || \ iface == PHY_INTERFACE_MODE_GMII) /* STiH4xx register definitions (STiH407/STiH410 families) @@ -82,13 +77,9 @@ * 001-RGMII * 010-SGMII * 100-RMII + * These are the DW MAC phy_intf_sel values. */ #define MII_PHY_SEL_MASK GENMASK(4, 2) -#define ETH_PHY_SEL_RMII BIT(4) -#define ETH_PHY_SEL_SGMII BIT(3) -#define ETH_PHY_SEL_RGMII BIT(2) -#define ETH_PHY_SEL_GMII 0x0 -#define ETH_PHY_SEL_MII 0x0 struct sti_dwmac { phy_interface_t interface; /* MII interface */ @@ -107,15 +98,6 @@ struct sti_dwmac_of_data { void (*fix_retime_src)(void *priv, int speed, unsigned int mode); }; -static u32 phy_intf_sels[] = { - [PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII, - [PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII, - [PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII, - [PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII, - [PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII, - [PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII, -}; - enum { TX_RETIME_SRC_NA = 0, TX_RETIME_SRC_TXCLK = 1, @@ -148,7 +130,7 @@ static void stih4xx_fix_retime_src(void *priv, int spd, unsigned int mode) src = TX_RETIME_SRC_CLKGEN; freq = DWMAC_50MHZ; } - } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) { + } else if (phy_interface_mode_is_rgmii(dwmac->interface)) { /* On GiGa clk source can be either ext or from clkgen */ freq = rgmii_clock(spd); @@ -164,19 +146,28 @@ static void stih4xx_fix_retime_src(void *priv, int spd, unsigned int mode) stih4xx_tx_retime_val[src]); } -static int sti_dwmac_set_mode(struct sti_dwmac *dwmac) +static int sti_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel) { - struct regmap *regmap = dwmac->regmap; - int iface = dwmac->interface; - u32 reg = dwmac->ctrl_reg; - u32 val; + struct sti_dwmac *dwmac = bsp_priv; + struct regmap *regmap; + u32 reg, val; + + regmap = dwmac->regmap; + reg = dwmac->ctrl_reg; if (dwmac->gmac_en) regmap_update_bits(regmap, reg, EN_MASK, EN); - regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]); + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_SGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) + phy_intf_sel = PHY_INTF_SEL_GMII_MII; - val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; + regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, + FIELD_PREP(MII_PHY_SEL_MASK, phy_intf_sel)); + + val = (dwmac->interface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; regmap_update_bits(regmap, reg, ENMII_MASK, val); dwmac->fix_retime_src(dwmac, dwmac->speed, 0); @@ -238,6 +229,20 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, return 0; } +static int sti_dwmac_init(struct device *dev, void *bsp_priv) +{ + struct sti_dwmac *dwmac = bsp_priv; + + return clk_prepare_enable(dwmac->clk); +} + +static void sti_dwmac_exit(struct device *dev, void *bsp_priv) +{ + struct sti_dwmac *dwmac = bsp_priv; + + clk_disable_unprepare(dwmac->clk); +} + static int sti_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -273,60 +278,14 @@ static int sti_dwmac_probe(struct platform_device *pdev) dwmac->fix_retime_src = data->fix_retime_src; plat_dat->bsp_priv = dwmac; + plat_dat->set_phy_intf_sel = sti_set_phy_intf_sel; plat_dat->fix_mac_speed = data->fix_retime_src; + plat_dat->init = sti_dwmac_init; + plat_dat->exit = sti_dwmac_exit; - ret = clk_prepare_enable(dwmac->clk); - if (ret) - return ret; - - ret = sti_dwmac_set_mode(dwmac); - if (ret) - goto disable_clk; - - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - if (ret) - goto disable_clk; - - return 0; - -disable_clk: - clk_disable_unprepare(dwmac->clk); - - return ret; -} - -static void sti_dwmac_remove(struct platform_device *pdev) -{ - struct sti_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); - - stmmac_dvr_remove(&pdev->dev); - - clk_disable_unprepare(dwmac->clk); -} - -static int sti_dwmac_suspend(struct device *dev) -{ - struct sti_dwmac *dwmac = get_stmmac_bsp_priv(dev); - int ret = stmmac_suspend(dev); - - clk_disable_unprepare(dwmac->clk); - - return ret; + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } -static int sti_dwmac_resume(struct device *dev) -{ - struct sti_dwmac *dwmac = get_stmmac_bsp_priv(dev); - - clk_prepare_enable(dwmac->clk); - sti_dwmac_set_mode(dwmac); - - return stmmac_resume(dev); -} - -static DEFINE_SIMPLE_DEV_PM_OPS(sti_dwmac_pm_ops, sti_dwmac_suspend, - sti_dwmac_resume); - static const struct sti_dwmac_of_data stih4xx_dwmac_data = { .fix_retime_src = stih4xx_fix_retime_src, }; @@ -339,10 +298,9 @@ MODULE_DEVICE_TABLE(of, sti_dwmac_match); static struct platform_driver sti_dwmac_driver = { .probe = sti_dwmac_probe, - .remove = sti_dwmac_remove, .driver = { .name = "sti-dwmac", - .pm = pm_sleep_ptr(&sti_dwmac_pm_ops), + .pm = &stmmac_pltfr_pm_ops, .of_match_table = sti_dwmac_match, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c index c3d321192581..e1b260ed4790 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -47,23 +47,18 @@ *------------------------------------------ */ #define SYSCFG_PMCR_ETH_SEL_MII BIT(20) -#define SYSCFG_PMCR_ETH_SEL_RGMII BIT(21) -#define SYSCFG_PMCR_ETH_SEL_RMII BIT(23) -#define SYSCFG_PMCR_ETH_SEL_GMII 0 +#define SYSCFG_PMCR_PHY_INTF_SEL_MASK GENMASK(23, 21) #define SYSCFG_MCU_ETH_SEL_MII 0 #define SYSCFG_MCU_ETH_SEL_RMII 1 /* STM32MP2 register definitions */ #define SYSCFG_MP2_ETH_MASK GENMASK(31, 0) +#define SYSCFG_ETHCR_ETH_SEL_MASK GENMASK(6, 4) #define SYSCFG_ETHCR_ETH_PTP_CLK_SEL BIT(2) #define SYSCFG_ETHCR_ETH_CLK_SEL BIT(1) #define SYSCFG_ETHCR_ETH_REF_CLK_SEL BIT(0) -#define SYSCFG_ETHCR_ETH_SEL_MII 0 -#define SYSCFG_ETHCR_ETH_SEL_RGMII BIT(4) -#define SYSCFG_ETHCR_ETH_SEL_RMII BIT(6) - /* STM32MPx register definitions * * Below table summarizes the clock requirement and clock sources for @@ -119,7 +114,7 @@ struct stm32_ops { u32 syscfg_clr_off; }; -static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume) +static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac) { int ret; @@ -127,11 +122,9 @@ static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume) if (ret) goto err_clk_tx; - if (!dwmac->ops->clk_rx_enable_in_suspend || !resume) { - ret = clk_prepare_enable(dwmac->clk_rx); - if (ret) - goto err_clk_rx; - } + ret = clk_prepare_enable(dwmac->clk_rx); + if (ret) + goto err_clk_rx; ret = clk_prepare_enable(dwmac->syscfg_clk); if (ret) @@ -148,15 +141,14 @@ static int stm32_dwmac_clk_enable(struct stm32_dwmac *dwmac, bool resume) err_clk_eth_ck: clk_disable_unprepare(dwmac->syscfg_clk); err_syscfg_clk: - if (!dwmac->ops->clk_rx_enable_in_suspend || !resume) - clk_disable_unprepare(dwmac->clk_rx); + clk_disable_unprepare(dwmac->clk_rx); err_clk_rx: clk_disable_unprepare(dwmac->clk_tx); err_clk_tx: return ret; } -static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat, bool resume) +static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; int ret; @@ -167,14 +159,14 @@ static int stm32_dwmac_init(struct plat_stmmacenet_data *plat_dat, bool resume) return ret; } - return stm32_dwmac_clk_enable(dwmac, resume); + return stm32_dwmac_clk_enable(dwmac); } static int stm32mp1_select_ethck_external(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; - switch (plat_dat->mac_interface) { + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: dwmac->enable_eth_ck = dwmac->ext_phyclk; return 0; @@ -196,7 +188,7 @@ static int stm32mp1_select_ethck_external(struct plat_stmmacenet_data *plat_dat) default: dwmac->enable_eth_ck = false; dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); return -EINVAL; } } @@ -209,7 +201,7 @@ static int stm32mp1_validate_ethck_rate(struct plat_stmmacenet_data *plat_dat) if (!dwmac->enable_eth_ck) return 0; - switch (plat_dat->mac_interface) { + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII: if (clk_rate == ETH_CK_F_25M) @@ -231,17 +223,20 @@ static int stm32mp1_validate_ethck_rate(struct plat_stmmacenet_data *plat_dat) } dev_err(dwmac->dev, "Mode %s does not match eth-ck frequency %d Hz", - phy_modes(plat_dat->mac_interface), clk_rate); + phy_modes(plat_dat->phy_interface), clk_rate); return -EINVAL; } -static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) +static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat, + u8 phy_intf_sel) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; u32 reg = dwmac->mode_reg; - int val = 0; + int val; - switch (plat_dat->mac_interface) { + val = FIELD_PREP(SYSCFG_PMCR_PHY_INTF_SEL_MASK, phy_intf_sel); + + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: /* * STM32MP15xx supports both MII and GMII, STM32MP13xx MII only. @@ -253,12 +248,10 @@ static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) val |= SYSCFG_PMCR_ETH_SEL_MII; break; case PHY_INTERFACE_MODE_GMII: - val = SYSCFG_PMCR_ETH_SEL_GMII; if (dwmac->enable_eth_ck) val |= SYSCFG_PMCR_ETH_CLK_SEL; break; case PHY_INTERFACE_MODE_RMII: - val = SYSCFG_PMCR_ETH_SEL_RMII; if (dwmac->enable_eth_ck) val |= SYSCFG_PMCR_ETH_REF_CLK_SEL; break; @@ -266,18 +259,17 @@ static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: - val = SYSCFG_PMCR_ETH_SEL_RGMII; if (dwmac->enable_eth_ck) val |= SYSCFG_PMCR_ETH_CLK_SEL; break; default: dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); /* Do not manage others interfaces */ return -EINVAL; } - dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface)); + dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->phy_interface)); /* Shift value at correct ethernet MAC offset in SYSCFG_PMCSETR */ val <<= ffs(dwmac->mode_mask) - ffs(SYSCFG_MP1_ETH_MASK); @@ -291,18 +283,20 @@ static int stm32mp1_configure_pmcr(struct plat_stmmacenet_data *plat_dat) dwmac->mode_mask, val); } -static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) +static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat, + u8 phy_intf_sel) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; u32 reg = dwmac->mode_reg; - int val = 0; + int val; - switch (plat_dat->mac_interface) { + val = FIELD_PREP(SYSCFG_ETHCR_ETH_SEL_MASK, phy_intf_sel); + + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: /* ETH_REF_CLK_SEL bit in SYSCFG register is not applicable in MII mode */ break; case PHY_INTERFACE_MODE_RMII: - val = SYSCFG_ETHCR_ETH_SEL_RMII; if (dwmac->enable_eth_ck) { /* Internal clock ETH_CLK of 50MHz from RCC is used */ val |= SYSCFG_ETHCR_ETH_REF_CLK_SEL; @@ -312,8 +306,6 @@ static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: - val = SYSCFG_ETHCR_ETH_SEL_RGMII; - fallthrough; case PHY_INTERFACE_MODE_GMII: if (dwmac->enable_eth_ck) { /* Internal clock ETH_CLK of 125MHz from RCC is used */ @@ -322,12 +314,12 @@ static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) break; default: dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); /* Do not manage others interfaces */ return -EINVAL; } - dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface)); + dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->phy_interface)); /* Select PTP (IEEE1588) clock selection from RCC (ck_ker_ethxptp) */ val |= SYSCFG_ETHCR_ETH_PTP_CLK_SEL; @@ -340,7 +332,7 @@ static int stm32mp2_configure_syscfg(struct plat_stmmacenet_data *plat_dat) static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) { struct stm32_dwmac *dwmac = plat_dat->bsp_priv; - int ret; + int phy_intf_sel, ret; ret = stm32mp1_select_ethck_external(plat_dat); if (ret) @@ -350,10 +342,19 @@ static int stm32mp1_set_mode(struct plat_stmmacenet_data *plat_dat) if (ret) return ret; + phy_intf_sel = stmmac_get_phy_intf_sel(plat_dat->phy_interface); + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) { + dev_err(dwmac->dev, "Mode %s not supported\n", + phy_modes(plat_dat->phy_interface)); + return phy_intf_sel < 0 ? phy_intf_sel : -EINVAL; + } + if (!dwmac->ops->is_mp2) - return stm32mp1_configure_pmcr(plat_dat); + return stm32mp1_configure_pmcr(plat_dat, phy_intf_sel); else - return stm32mp2_configure_syscfg(plat_dat); + return stm32mp2_configure_syscfg(plat_dat, phy_intf_sel); } static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) @@ -362,7 +363,7 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) u32 reg = dwmac->mode_reg; int val; - switch (plat_dat->mac_interface) { + switch (plat_dat->phy_interface) { case PHY_INTERFACE_MODE_MII: val = SYSCFG_MCU_ETH_SEL_MII; break; @@ -371,23 +372,21 @@ static int stm32mcu_set_mode(struct plat_stmmacenet_data *plat_dat) break; default: dev_err(dwmac->dev, "Mode %s not supported", - phy_modes(plat_dat->mac_interface)); + phy_modes(plat_dat->phy_interface)); /* Do not manage others interfaces */ return -EINVAL; } - dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->mac_interface)); + dev_dbg(dwmac->dev, "Mode %s", phy_modes(plat_dat->phy_interface)); return regmap_update_bits(dwmac->regmap, reg, SYSCFG_MCU_ETH_MASK, val << 23); } -static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac, bool suspend) +static void stm32_dwmac_clk_disable(struct stm32_dwmac *dwmac) { clk_disable_unprepare(dwmac->clk_tx); - if (!dwmac->ops->clk_rx_enable_in_suspend || !suspend) - clk_disable_unprepare(dwmac->clk_rx); - + clk_disable_unprepare(dwmac->clk_rx); clk_disable_unprepare(dwmac->syscfg_clk); if (dwmac->enable_eth_ck) clk_disable_unprepare(dwmac->clk_eth_ck); @@ -503,6 +502,26 @@ static int stm32mp1_parse_data(struct stm32_dwmac *dwmac, return err; } +static int stm32_dwmac_suspend(struct device *dev, void *bsp_priv) +{ + struct stm32_dwmac *dwmac = bsp_priv; + + stm32_dwmac_clk_disable(dwmac); + + return dwmac->ops->suspend ? dwmac->ops->suspend(dwmac) : 0; +} + +static int stm32_dwmac_resume(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + struct stm32_dwmac *dwmac = bsp_priv; + + if (dwmac->ops->resume) + dwmac->ops->resume(dwmac); + + return stm32_dwmac_init(priv->plat); +} + static int stm32_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; @@ -540,19 +559,35 @@ static int stm32_dwmac_probe(struct platform_device *pdev) plat_dat->flags |= STMMAC_FLAG_EN_TX_LPI_CLK_PHY_CAP; plat_dat->bsp_priv = dwmac; + plat_dat->suspend = stm32_dwmac_suspend; + plat_dat->resume = stm32_dwmac_resume; - ret = stm32_dwmac_init(plat_dat, false); + ret = stm32_dwmac_init(plat_dat); if (ret) return ret; + /* If this platform requires the clock to be running in suspend, + * prepare and enable the receive clock an additional time to keep + * it running. + */ + if (dwmac->ops->clk_rx_enable_in_suspend) { + ret = clk_prepare_enable(dwmac->clk_rx); + if (ret) + goto err_clk_disable; + } + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) - goto err_clk_disable; + goto err_clk_disable_suspend; return 0; +err_clk_disable_suspend: + if (dwmac->ops->clk_rx_enable_in_suspend) + clk_disable_unprepare(dwmac->clk_rx); + err_clk_disable: - stm32_dwmac_clk_disable(dwmac, false); + stm32_dwmac_clk_disable(dwmac); return ret; } @@ -565,7 +600,15 @@ static void stm32_dwmac_remove(struct platform_device *pdev) stmmac_dvr_remove(&pdev->dev); - stm32_dwmac_clk_disable(dwmac, false); + /* If this platform requires the clock to be running in suspend, + * we need to disable and unprepare the receive clock an additional + * time to balance the extra clk_prepare_enable() in the probe + * function. + */ + if (dwmac->ops->clk_rx_enable_in_suspend) + clk_disable_unprepare(dwmac->clk_rx); + + stm32_dwmac_clk_disable(dwmac); if (dwmac->irq_pwr_wakeup >= 0) { dev_pm_clear_wake_irq(&pdev->dev); @@ -583,50 +626,6 @@ static void stm32mp1_resume(struct stm32_dwmac *dwmac) clk_disable_unprepare(dwmac->clk_ethstp); } -#ifdef CONFIG_PM_SLEEP -static int stm32_dwmac_suspend(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - stm32_dwmac_clk_disable(dwmac, true); - - if (dwmac->ops->suspend) - ret = dwmac->ops->suspend(dwmac); - - return ret; -} - -static int stm32_dwmac_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct stm32_dwmac *dwmac = priv->plat->bsp_priv; - int ret; - - if (dwmac->ops->resume) - dwmac->ops->resume(dwmac); - - ret = stm32_dwmac_init(priv->plat, true); - if (ret) - return ret; - - ret = stmmac_resume(dev); - - return ret; -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(stm32_dwmac_pm_ops, - stm32_dwmac_suspend, stm32_dwmac_resume); - static struct stm32_ops stm32mcu_dwmac_data = { .set_mode = stm32mcu_set_mode }; @@ -674,7 +673,7 @@ static struct platform_driver stm32_dwmac_driver = { .remove = stm32_dwmac_remove, .driver = { .name = "stm32-dwmac", - .pm = &stm32_dwmac_pm_ops, + .pm = &stmmac_simple_pm_ops, .of_match_table = stm32_dwmac_match, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun55i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun55i.c new file mode 100644 index 000000000000..862df173d963 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun55i.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * dwmac-sun55i.c - Allwinner sun55i GMAC200 specific glue layer + * + * Copyright (C) 2025 Chen-Yu Tsai <wens@csie.org> + * + * syscon parts taken from dwmac-sun8i.c, which is + * + * Copyright (C) 2017 Corentin Labbe <clabbe.montjoie@gmail.com> + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <linux/stmmac.h> + +#include "stmmac.h" +#include "stmmac_platform.h" + +#define SYSCON_REG 0x34 + +/* RMII specific bits */ +#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */ +/* Generic system control EMAC_CLK bits */ +#define SYSCON_ETXDC_MASK GENMASK(12, 10) +#define SYSCON_ERXDC_MASK GENMASK(9, 5) +/* EMAC PHY Interface Type */ +#define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */ +#define SYSCON_ETCS_MASK GENMASK(1, 0) +#define SYSCON_ETCS_MII 0x0 +#define SYSCON_ETCS_EXT_GMII 0x1 +#define SYSCON_ETCS_INT_GMII 0x2 + +static int sun55i_gmac200_set_syscon(struct device *dev, + struct plat_stmmacenet_data *plat) +{ + struct device_node *node = dev->of_node; + struct regmap *regmap; + u32 val, reg = 0; + int ret; + + regmap = syscon_regmap_lookup_by_phandle(node, "syscon"); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), "Unable to map syscon\n"); + + if (!of_property_read_u32(node, "tx-internal-delay-ps", &val)) { + if (val % 100) + return dev_err_probe(dev, -EINVAL, + "tx-delay must be a multiple of 100ps\n"); + val /= 100; + dev_dbg(dev, "set tx-delay to %x\n", val); + if (!FIELD_FIT(SYSCON_ETXDC_MASK, val)) + return dev_err_probe(dev, -EINVAL, + "TX clock delay exceeds maximum (%u00ps > %lu00ps)\n", + val, FIELD_MAX(SYSCON_ETXDC_MASK)); + + reg |= FIELD_PREP(SYSCON_ETXDC_MASK, val); + } + + if (!of_property_read_u32(node, "rx-internal-delay-ps", &val)) { + if (val % 100) + return dev_err_probe(dev, -EINVAL, + "rx-delay must be a multiple of 100ps\n"); + val /= 100; + dev_dbg(dev, "set rx-delay to %x\n", val); + if (!FIELD_FIT(SYSCON_ERXDC_MASK, val)) + return dev_err_probe(dev, -EINVAL, + "RX clock delay exceeds maximum (%u00ps > %lu00ps)\n", + val, FIELD_MAX(SYSCON_ERXDC_MASK)); + + reg |= FIELD_PREP(SYSCON_ERXDC_MASK, val); + } + + switch (plat->phy_interface) { + case PHY_INTERFACE_MODE_MII: + /* default */ + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII; + break; + case PHY_INTERFACE_MODE_RMII: + reg |= SYSCON_RMII_EN; + break; + default: + return dev_err_probe(dev, -EINVAL, "Unsupported interface mode: %s", + phy_modes(plat->phy_interface)); + } + + ret = regmap_write(regmap, SYSCON_REG, reg); + if (ret < 0) + return dev_err_probe(dev, ret, "Failed to write to syscon\n"); + + return 0; +} + +static int sun55i_gmac200_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + struct device *dev = &pdev->dev; + struct clk *clk; + 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); + + /* BSP disables it */ + plat_dat->flags |= STMMAC_FLAG_SPH_DISABLE; + plat_dat->host_dma_width = 32; + + ret = sun55i_gmac200_set_syscon(dev, plat_dat); + if (ret) + return ret; + + clk = devm_clk_get_enabled(dev, "mbus"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "Failed to get or enable MBUS clock\n"); + + ret = devm_regulator_get_enable_optional(dev, "phy"); + if (ret) + return dev_err_probe(dev, ret, "Failed to get or enable PHY supply\n"); + + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); +} + +static const struct of_device_id sun55i_gmac200_match[] = { + { .compatible = "allwinner,sun55i-a523-gmac200" }, + { } +}; +MODULE_DEVICE_TABLE(of, sun55i_gmac200_match); + +static struct platform_driver sun55i_gmac200_driver = { + .probe = sun55i_gmac200_probe, + .driver = { + .name = "dwmac-sun55i", + .pm = &stmmac_pltfr_pm_ops, + .of_match_table = sun55i_gmac200_match, + }, +}; +module_platform_driver(sun55i_gmac200_driver); + +MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>"); +MODULE_DESCRIPTION("Allwinner sun55i GMAC200 specific glue layer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 85723a78793a..8aa496ac85cc 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -31,10 +31,6 @@ */ /* struct emac_variant - Describe dwmac-sun8i hardware variant - * @default_syscon_value: The default value of the EMAC register in syscon - * This value is used for disabling properly EMAC - * and used as a good starting value in case of the - * boot process(uboot) leave some stuff. * @syscon_field reg_field for the syscon's gmac register * @soc_has_internal_phy: Does the MAC embed an internal PHY * @support_mii: Does the MAC handle MII @@ -48,7 +44,6 @@ * value of zero indicates this is not supported. */ struct emac_variant { - u32 default_syscon_value; const struct reg_field *syscon_field; bool soc_has_internal_phy; bool support_mii; @@ -94,7 +89,6 @@ static const struct reg_field sun8i_ccu_reg_field = { }; static const struct emac_variant emac_variant_h3 = { - .default_syscon_value = 0x58000, .syscon_field = &sun8i_syscon_reg_field, .soc_has_internal_phy = true, .support_mii = true, @@ -105,14 +99,12 @@ static const struct emac_variant emac_variant_h3 = { }; static const struct emac_variant emac_variant_v3s = { - .default_syscon_value = 0x38000, .syscon_field = &sun8i_syscon_reg_field, .soc_has_internal_phy = true, .support_mii = true }; static const struct emac_variant emac_variant_a83t = { - .default_syscon_value = 0, .syscon_field = &sun8i_syscon_reg_field, .soc_has_internal_phy = false, .support_mii = true, @@ -122,7 +114,6 @@ static const struct emac_variant emac_variant_a83t = { }; static const struct emac_variant emac_variant_r40 = { - .default_syscon_value = 0, .syscon_field = &sun8i_ccu_reg_field, .support_mii = true, .support_rgmii = true, @@ -130,7 +121,6 @@ static const struct emac_variant emac_variant_r40 = { }; static const struct emac_variant emac_variant_a64 = { - .default_syscon_value = 0, .syscon_field = &sun8i_syscon_reg_field, .soc_has_internal_phy = false, .support_mii = true, @@ -141,7 +131,6 @@ static const struct emac_variant emac_variant_a64 = { }; static const struct emac_variant emac_variant_h6 = { - .default_syscon_value = 0x50000, .syscon_field = &sun8i_syscon_reg_field, /* The "Internal PHY" of H6 is not on the die. It's on the * co-packaged AC200 chip instead. @@ -582,16 +571,16 @@ static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = { static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv); -static int sun8i_dwmac_init(struct platform_device *pdev, void *priv) +static int sun8i_dwmac_init(struct device *dev, void *priv) { - struct net_device *ndev = platform_get_drvdata(pdev); + struct net_device *ndev = dev_get_drvdata(dev); struct sunxi_priv_data *gmac = priv; int ret; if (gmac->regulator) { ret = regulator_enable(gmac->regulator); if (ret) { - dev_err(&pdev->dev, "Fail to enable regulator\n"); + dev_err(dev, "Fail to enable regulator\n"); return ret; } } @@ -933,25 +922,11 @@ static int sun8i_dwmac_set_syscon(struct device *dev, struct sunxi_priv_data *gmac = plat->bsp_priv; struct device_node *node = dev->of_node; int ret; - u32 reg, val; - - ret = regmap_field_read(gmac->regmap_field, &val); - if (ret) { - dev_err(dev, "Fail to read from regmap field.\n"); - return ret; - } - - reg = gmac->variant->default_syscon_value; - if (reg != val) - dev_warn(dev, - "Current syscon value is not the default %x (expect %x)\n", - val, reg); + u32 reg = 0, val; if (gmac->variant->soc_has_internal_phy) { if (of_property_read_bool(node, "allwinner,leds-active-low")) reg |= H3_EPHY_LED_POL; - else - reg &= ~H3_EPHY_LED_POL; /* Force EPHY xtal frequency to 24MHz. */ reg |= H3_EPHY_CLK_SEL; @@ -964,12 +939,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev, /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY * address. No need to mask it again. */ - reg |= 1 << H3_EPHY_ADDR_SHIFT; - } else { - /* For SoCs without internal PHY the PHY selection bit should be - * set to 0 (external PHY). - */ - reg &= ~H3_EPHY_SELECT; + reg |= ret << H3_EPHY_ADDR_SHIFT; } if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) { @@ -980,8 +950,6 @@ static int sun8i_dwmac_set_syscon(struct device *dev, val /= 100; dev_dbg(dev, "set tx-delay to %x\n", val); if (val <= gmac->variant->tx_delay_max) { - reg &= ~(gmac->variant->tx_delay_max << - SYSCON_ETXDC_SHIFT); reg |= (val << SYSCON_ETXDC_SHIFT); } else { dev_err(dev, "Invalid TX clock delay: %d\n", @@ -998,8 +966,6 @@ static int sun8i_dwmac_set_syscon(struct device *dev, val /= 100; dev_dbg(dev, "set rx-delay to %x\n", val); if (val <= gmac->variant->rx_delay_max) { - reg &= ~(gmac->variant->rx_delay_max << - SYSCON_ERXDC_SHIFT); reg |= (val << SYSCON_ERXDC_SHIFT); } else { dev_err(dev, "Invalid RX clock delay: %d\n", @@ -1008,12 +974,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev, } } - /* Clear interface mode bits */ - reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT); - if (gmac->variant->support_rmii) - reg &= ~SYSCON_RMII_EN; - - switch (plat->mac_interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: /* default */ break; @@ -1028,7 +989,7 @@ static int sun8i_dwmac_set_syscon(struct device *dev, break; default: dev_err(dev, "Unsupported interface mode: %s", - phy_modes(plat->mac_interface)); + phy_modes(plat->phy_interface)); return -EINVAL; } @@ -1039,12 +1000,12 @@ static int sun8i_dwmac_set_syscon(struct device *dev, static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac) { - u32 reg = gmac->variant->default_syscon_value; - - regmap_field_write(gmac->regmap_field, reg); + if (gmac->variant->soc_has_internal_phy) + regmap_field_write(gmac->regmap_field, + (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT)); } -static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv) +static void sun8i_dwmac_exit(struct device *dev, void *priv) { struct sunxi_priv_data *gmac = priv; @@ -1079,15 +1040,10 @@ static const struct stmmac_ops sun8i_dwmac_ops = { .set_mac_loopback = sun8i_dwmac_set_mac_loopback, }; -static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) +static int sun8i_dwmac_setup(void *ppriv, struct mac_device_info *mac) { - struct mac_device_info *mac; struct stmmac_priv *priv = ppriv; - mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); - if (!mac) - return NULL; - mac->pcsr = priv->ioaddr; mac->mac = &sun8i_dwmac_ops; mac->dma = &sun8i_dwmac_dma_ops; @@ -1118,7 +1074,7 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv) /* Synopsys Id is not available */ priv->synopsys_id = 0; - return mac; + return 0; } static struct regmap *sun8i_dwmac_get_syscon_from_dev(struct device_node *node) @@ -1231,7 +1187,7 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) plat_dat->bsp_priv = gmac; plat_dat->init = sun8i_dwmac_init; plat_dat->exit = sun8i_dwmac_exit; - plat_dat->setup = sun8i_dwmac_setup; + plat_dat->mac_setup = sun8i_dwmac_setup; plat_dat->tx_fifo_size = 4096; plat_dat->rx_fifo_size = 16384; @@ -1239,14 +1195,10 @@ static int sun8i_dwmac_probe(struct platform_device *pdev) if (ret) return ret; - ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv); + ret = stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); if (ret) goto dwmac_syscon; - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - if (ret) - goto dwmac_exit; - ndev = dev_get_drvdata(&pdev->dev); priv = netdev_priv(ndev); @@ -1283,9 +1235,7 @@ dwmac_mux: clk_put(gmac->ephy_clk); dwmac_remove: pm_runtime_put_noidle(&pdev->dev); - stmmac_dvr_remove(&pdev->dev); -dwmac_exit: - sun8i_dwmac_exit(pdev, gmac); + stmmac_pltfr_remove(pdev); dwmac_syscon: sun8i_dwmac_unset_syscon(gmac); @@ -1315,7 +1265,7 @@ static void sun8i_dwmac_shutdown(struct platform_device *pdev) struct stmmac_priv *priv = netdev_priv(ndev); struct sunxi_priv_data *gmac = priv->plat->bsp_priv; - sun8i_dwmac_exit(pdev, gmac); + sun8i_dwmac_exit(&pdev->dev, gmac); } static const struct of_device_id sun8i_dwmac_match[] = { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index 9f098ff0ff05..52593ba3a3a3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c @@ -27,7 +27,7 @@ struct sunxi_priv_data { #define SUN7I_GMAC_GMII_RGMII_RATE 125000000 #define SUN7I_GMAC_MII_RATE 25000000 -static int sun7i_gmac_init(struct platform_device *pdev, void *priv) +static int sun7i_gmac_init(struct device *dev, void *priv) { struct sunxi_priv_data *gmac = priv; int ret = 0; @@ -58,7 +58,7 @@ static int sun7i_gmac_init(struct platform_device *pdev, void *priv) return ret; } -static void sun7i_gmac_exit(struct platform_device *pdev, void *priv) +static void sun7i_gmac_exit(struct device *dev, void *priv) { struct sunxi_priv_data *gmac = priv; @@ -72,28 +72,28 @@ static void sun7i_gmac_exit(struct platform_device *pdev, void *priv) regulator_disable(gmac->regulator); } -static void sun7i_fix_speed(void *priv, int speed, unsigned int mode) +static int sun7i_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { - struct sunxi_priv_data *gmac = priv; - - /* only GMII mode requires us to reconfigure the clock lines */ - if (gmac->interface != PHY_INTERFACE_MODE_GMII) - return; - - if (gmac->clk_enabled) { - clk_disable(gmac->tx_clk); - gmac->clk_enabled = 0; - } - clk_unprepare(gmac->tx_clk); - - if (speed == 1000) { - clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); - clk_prepare_enable(gmac->tx_clk); - gmac->clk_enabled = 1; - } else { - clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE); - clk_prepare(gmac->tx_clk); + struct sunxi_priv_data *gmac = bsp_priv; + + if (interface == PHY_INTERFACE_MODE_GMII) { + if (gmac->clk_enabled) { + clk_disable(gmac->tx_clk); + gmac->clk_enabled = 0; + } + clk_unprepare(gmac->tx_clk); + + if (speed == 1000) { + clk_set_rate(gmac->tx_clk, SUN7I_GMAC_GMII_RGMII_RATE); + clk_prepare_enable(gmac->tx_clk); + gmac->clk_enabled = 1; + } else { + clk_set_rate(gmac->tx_clk, SUN7I_GMAC_MII_RATE); + clk_prepare(gmac->tx_clk); + } } + return 0; } static int sun7i_gmac_probe(struct platform_device *pdev) @@ -136,28 +136,15 @@ static int sun7i_gmac_probe(struct platform_device *pdev) /* platform data specifying hardware features and callbacks. * hardware features were copied from Allwinner drivers. */ plat_dat->tx_coe = 1; - plat_dat->has_gmac = true; + plat_dat->core_type = DWMAC_CORE_GMAC; plat_dat->bsp_priv = gmac; plat_dat->init = sun7i_gmac_init; plat_dat->exit = sun7i_gmac_exit; - plat_dat->fix_mac_speed = sun7i_fix_speed; + plat_dat->set_clk_tx_rate = sun7i_set_clk_tx_rate; plat_dat->tx_fifo_size = 4096; plat_dat->rx_fifo_size = 16384; - ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); - if (ret) - return ret; - - ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); - if (ret) - goto err_gmac_exit; - - return 0; - -err_gmac_exit: - sun7i_gmac_exit(pdev, plat_dat->bsp_priv); - - return ret; + return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res); } static const struct of_device_id sun7i_dwmac_match[] = { @@ -168,7 +155,6 @@ MODULE_DEVICE_TABLE(of, sun7i_dwmac_match); static struct platform_driver sun7i_dwmac_driver = { .probe = sun7i_gmac_probe, - .remove = stmmac_pltfr_remove, .driver = { .name = "sun7i-dwmac", .pm = &stmmac_pltfr_pm_ops, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c index dc903b846b1b..d765acbe3754 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-tegra.c @@ -308,7 +308,7 @@ static int tegra_mgbe_probe(struct platform_device *pdev) goto disable_clks; } - plat->has_xgmac = 1; + plat->core_type = DWMAC_CORE_XGMAC; plat->flags |= STMMAC_FLAG_TSO_EN; plat->pmt = 1; plat->bsp_priv = mgbe; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c index c72ee759aae5..e291028ba56e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-thead.c @@ -56,7 +56,7 @@ static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) struct thead_dwmac *dwmac = plat->bsp_priv; u32 phyif; - switch (plat->mac_interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: phyif = PHY_INTF_MII_GMII; break; @@ -67,8 +67,8 @@ static int thead_dwmac_set_phy_if(struct plat_stmmacenet_data *plat) phyif = PHY_INTF_RGMII; break; default: - dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->mac_interface); + dev_err(dwmac->dev, "unsupported phy interface %s\n", + phy_modes(plat->phy_interface)); return -EINVAL; } @@ -81,7 +81,7 @@ static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) struct thead_dwmac *dwmac = plat->bsp_priv; u32 txclk_dir; - switch (plat->mac_interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: txclk_dir = TXCLK_DIR_INPUT; break; @@ -92,8 +92,8 @@ static int thead_dwmac_set_txclk_dir(struct plat_stmmacenet_data *plat) txclk_dir = TXCLK_DIR_OUTPUT; break; default: - dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->mac_interface); + dev_err(dwmac->dev, "unsupported phy interface %s\n", + phy_modes(plat->phy_interface)); return -EINVAL; } @@ -112,7 +112,7 @@ static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, plat = dwmac->plat; - switch (plat->mac_interface) { + switch (plat->phy_interface) { /* For MII, rxc/txc is provided by phy */ case PHY_INTERFACE_MODE_MII: return 0; @@ -143,8 +143,8 @@ static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, return 0; default: - dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->mac_interface); + dev_err(dwmac->dev, "unsupported phy interface %s\n", + phy_modes(plat->phy_interface)); return -EINVAL; } } @@ -152,9 +152,9 @@ static int thead_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) { struct thead_dwmac *dwmac = plat->bsp_priv; - u32 reg; + u32 reg, div; - switch (plat->mac_interface) { + switch (plat->phy_interface) { case PHY_INTERFACE_MODE_MII: reg = GMAC_RX_CLK_EN | GMAC_TX_CLK_EN; break; @@ -164,14 +164,21 @@ static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) case PHY_INTERFACE_MODE_RGMII_RXID: case PHY_INTERFACE_MODE_RGMII_TXID: /* use pll */ + div = clk_get_rate(plat->stmmac_clk) / rgmii_clock(SPEED_1000); + reg = FIELD_PREP(GMAC_PLLCLK_DIV_EN, 1) | + FIELD_PREP(GMAC_PLLCLK_DIV_NUM, div); + + writel(0, dwmac->apb_base + GMAC_PLLCLK_DIV); + writel(reg, dwmac->apb_base + GMAC_PLLCLK_DIV); + writel(GMAC_GTXCLK_SEL_PLL, dwmac->apb_base + GMAC_GTXCLK_SEL); reg = GMAC_TX_CLK_EN | GMAC_TX_CLK_N_EN | GMAC_TX_CLK_OUT_EN | GMAC_RX_CLK_EN | GMAC_RX_CLK_N_EN; break; default: - dev_err(dwmac->dev, "unsupported phy interface %d\n", - plat->mac_interface); + dev_err(dwmac->dev, "unsupported phy interface %s\n", + phy_modes(plat->phy_interface)); return -EINVAL; } @@ -179,7 +186,7 @@ static int thead_dwmac_enable_clk(struct plat_stmmacenet_data *plat) return 0; } -static int thead_dwmac_init(struct platform_device *pdev, void *priv) +static int thead_dwmac_init(struct device *dev, void *priv) { struct thead_dwmac *dwmac = priv; unsigned int reg; @@ -211,6 +218,7 @@ static int thead_dwmac_probe(struct platform_device *pdev) struct stmmac_resources stmmac_res; struct plat_stmmacenet_data *plat; struct thead_dwmac *dwmac; + struct clk *apb_clk; void __iomem *apb; int ret; @@ -224,6 +232,19 @@ static int thead_dwmac_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(plat), "dt configuration failed\n"); + /* + * The APB clock is essential for accessing glue registers. However, + * old devicetrees don't describe it correctly. We continue to probe + * and emit a warning if it isn't present. + */ + apb_clk = devm_clk_get_enabled(&pdev->dev, "apb"); + if (PTR_ERR(apb_clk) == -ENOENT) + dev_warn(&pdev->dev, + "cannot get apb clock, link may break after speed changes\n"); + else if (IS_ERR(apb_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(apb_clk), + "failed to get apb clock\n"); + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); if (!dwmac) return -ENOMEM; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c index 33cf99797df5..9497b13a5753 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-visconti.c @@ -42,69 +42,45 @@ #define ETHER_CLK_SEL_RX_TX_CLK_EN (ETHER_CLK_SEL_RX_CLK_EN | ETHER_CLK_SEL_TX_CLK_EN) -#define ETHER_CONFIG_INTF_MII 0 -#define ETHER_CONFIG_INTF_RGMII BIT(0) -#define ETHER_CONFIG_INTF_RMII BIT(2) - struct visconti_eth { void __iomem *reg; - u32 phy_intf_sel; struct clk *phy_ref_clk; struct device *dev; - spinlock_t lock; /* lock to protect register update */ }; -static void visconti_eth_fix_mac_speed(void *priv, int speed, unsigned int mode) +static int visconti_eth_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, + phy_interface_t interface, int speed) { - struct visconti_eth *dwmac = priv; - struct net_device *netdev = dev_get_drvdata(dwmac->dev); - unsigned int val, clk_sel_val = 0; - unsigned long flags; - - spin_lock_irqsave(&dwmac->lock, flags); - - /* adjust link */ - val = readl(dwmac->reg + MAC_CTRL_REG); - val &= ~(GMAC_CONFIG_PS | GMAC_CONFIG_FES); - - switch (speed) { - case SPEED_1000: - if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) - clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; - break; - case SPEED_100: - if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) - clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_25M; - if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) - clk_sel_val = ETHER_CLK_SEL_DIV_SEL_2; - val |= GMAC_CONFIG_PS | GMAC_CONFIG_FES; - break; - case SPEED_10: - if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RGMII) - clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_2P5M; - if (dwmac->phy_intf_sel == ETHER_CONFIG_INTF_RMII) - clk_sel_val = ETHER_CLK_SEL_DIV_SEL_20; - val |= GMAC_CONFIG_PS; - break; - default: - /* No bit control */ - netdev_err(netdev, "Unsupported speed request (%d)", speed); - spin_unlock_irqrestore(&dwmac->lock, flags); - return; - } - - writel(val, dwmac->reg + MAC_CTRL_REG); - - /* Stop internal clock */ - val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); - val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN); - val |= ETHER_CLK_SEL_TX_O_E_N_IN; - writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + struct visconti_eth *dwmac = bsp_priv; + unsigned long clk_sel, val; + + if (phy_interface_mode_is_rgmii(interface)) { + switch (speed) { + case SPEED_1000: + clk_sel = ETHER_CLK_SEL_FREQ_SEL_125M; + break; + + case SPEED_100: + clk_sel = ETHER_CLK_SEL_FREQ_SEL_25M; + break; + + case SPEED_10: + clk_sel = ETHER_CLK_SEL_FREQ_SEL_2P5M; + break; + + default: + return -EINVAL; + } + + /* Stop internal clock */ + val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); + val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | + ETHER_CLK_SEL_RX_TX_CLK_EN); + val |= ETHER_CLK_SEL_TX_O_E_N_IN; + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); - /* Set Clock-Mux, Start clock, Set TX_O direction */ - switch (dwmac->phy_intf_sel) { - case ETHER_CONFIG_INTF_RGMII: - val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC; + /* Set Clock-Mux, Start clock, Set TX_O direction */ + val = clk_sel | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC; writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); val |= ETHER_CLK_SEL_RX_TX_CLK_EN; @@ -112,11 +88,32 @@ static void visconti_eth_fix_mac_speed(void *priv, int speed, unsigned int mode) val &= ~ETHER_CLK_SEL_TX_O_E_N_IN; writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); - break; - case ETHER_CONFIG_INTF_RMII: - val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV | - ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | ETHER_CLK_SEL_TX_O_E_N_IN | - ETHER_CLK_SEL_RMII_CLK_SEL_RX_C; + } else if (interface == PHY_INTERFACE_MODE_RMII) { + switch (speed) { + case SPEED_100: + clk_sel = ETHER_CLK_SEL_DIV_SEL_2; + break; + + case SPEED_10: + clk_sel = ETHER_CLK_SEL_DIV_SEL_20; + break; + + default: + return -EINVAL; + } + + /* Stop internal clock */ + val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); + val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | + ETHER_CLK_SEL_RX_TX_CLK_EN); + val |= ETHER_CLK_SEL_TX_O_E_N_IN; + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + + /* Set Clock-Mux, Start clock, Set TX_O direction */ + val = clk_sel | ETHER_CLK_SEL_RX_CLK_EXT_SEL_DIV | + ETHER_CLK_SEL_TX_CLK_EXT_SEL_DIV | + ETHER_CLK_SEL_TX_O_E_N_IN | + ETHER_CLK_SEL_RMII_CLK_SEL_RX_C; writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); val |= ETHER_CLK_SEL_RMII_CLK_RST; @@ -124,46 +121,42 @@ static void visconti_eth_fix_mac_speed(void *priv, int speed, unsigned int mode) val |= ETHER_CLK_SEL_RMII_CLK_EN | ETHER_CLK_SEL_RX_TX_CLK_EN; writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); - break; - case ETHER_CONFIG_INTF_MII: - default: - val = clk_sel_val | ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC | - ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | ETHER_CLK_SEL_TX_O_E_N_IN; + } else { + /* Stop internal clock */ + val = readl(dwmac->reg + REG_ETHER_CLOCK_SEL); + val &= ~(ETHER_CLK_SEL_RMII_CLK_EN | + ETHER_CLK_SEL_RX_TX_CLK_EN); + val |= ETHER_CLK_SEL_TX_O_E_N_IN; + writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); + + /* Set Clock-Mux, Start clock, Set TX_O direction */ + val = ETHER_CLK_SEL_RX_CLK_EXT_SEL_RXC | + ETHER_CLK_SEL_TX_CLK_EXT_SEL_TXC | + ETHER_CLK_SEL_TX_O_E_N_IN; writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); val |= ETHER_CLK_SEL_RX_TX_CLK_EN; writel(val, dwmac->reg + REG_ETHER_CLOCK_SEL); - break; } - spin_unlock_irqrestore(&dwmac->lock, flags); + return 0; } static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmacenet_data *plat_dat) { struct visconti_eth *dwmac = plat_dat->bsp_priv; - unsigned int reg_val, clk_sel_val; - - switch (plat_dat->phy_interface) { - case PHY_INTERFACE_MODE_RGMII: - case PHY_INTERFACE_MODE_RGMII_ID: - case PHY_INTERFACE_MODE_RGMII_RXID: - case PHY_INTERFACE_MODE_RGMII_TXID: - dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RGMII; - break; - case PHY_INTERFACE_MODE_MII: - dwmac->phy_intf_sel = ETHER_CONFIG_INTF_MII; - break; - case PHY_INTERFACE_MODE_RMII: - dwmac->phy_intf_sel = ETHER_CONFIG_INTF_RMII; - break; - default: + unsigned int clk_sel_val; + int phy_intf_sel; + + phy_intf_sel = stmmac_get_phy_intf_sel(plat_dat->phy_interface); + if (phy_intf_sel != PHY_INTF_SEL_GMII_MII && + phy_intf_sel != PHY_INTF_SEL_RGMII && + phy_intf_sel != PHY_INTF_SEL_RMII) { dev_err(&pdev->dev, "Unsupported phy-mode (%d)\n", plat_dat->phy_interface); return -EOPNOTSUPP; } - reg_val = dwmac->phy_intf_sel; - writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); + writel(phy_intf_sel, dwmac->reg + REG_ETHER_CONTROL); /* Enable TX/RX clock */ clk_sel_val = ETHER_CLK_SEL_FREQ_SEL_125M; @@ -173,8 +166,8 @@ static int visconti_eth_init_hw(struct platform_device *pdev, struct plat_stmmac dwmac->reg + REG_ETHER_CLOCK_SEL); /* release internal-reset */ - reg_val |= ETHER_ETH_CONTROL_RESET; - writel(reg_val, dwmac->reg + REG_ETHER_CONTROL); + phy_intf_sel |= ETHER_ETH_CONTROL_RESET; + writel(phy_intf_sel, dwmac->reg + REG_ETHER_CONTROL); return 0; } @@ -228,11 +221,10 @@ static int visconti_eth_dwmac_probe(struct platform_device *pdev) if (!dwmac) return -ENOMEM; - spin_lock_init(&dwmac->lock); dwmac->reg = stmmac_res.addr; dwmac->dev = &pdev->dev; plat_dat->bsp_priv = dwmac; - plat_dat->fix_mac_speed = visconti_eth_fix_mac_speed; + plat_dat->set_clk_tx_rate = visconti_eth_set_clk_tx_rate; ret = visconti_eth_clock_probe(pdev, plat_dat); if (ret) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h index 0c011a47d5a3..697bba641e05 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h @@ -38,11 +38,10 @@ #define GMAC_INT_DISABLE_PCSAN BIT(2) #define GMAC_INT_DISABLE_PMT BIT(3) #define GMAC_INT_DISABLE_TIMESTAMP BIT(9) -#define GMAC_INT_DISABLE_PCS (GMAC_INT_DISABLE_RGMII | \ +#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_RGMII | \ GMAC_INT_DISABLE_PCSLINK | \ - GMAC_INT_DISABLE_PCSAN) -#define GMAC_INT_DEFAULT_MASK (GMAC_INT_DISABLE_TIMESTAMP | \ - GMAC_INT_DISABLE_PCS) + GMAC_INT_DISABLE_PCSAN | \ + GMAC_INT_DISABLE_TIMESTAMP) /* PMT Control and Status */ #define GMAC_PMT 0x0000002c diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index 56b76aaa58f0..a2ae136d2c0e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -22,47 +22,35 @@ #include "stmmac_ptp.h" #include "dwmac1000.h" +static int dwmac1000_pcs_init(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.pcs) + return 0; + + return stmmac_integrated_pcs_init(priv, GMAC_PCS_BASE, + GMAC_INT_DISABLE_PCSLINK | + GMAC_INT_DISABLE_PCSAN); +} + static void dwmac1000_core_init(struct mac_device_info *hw, struct net_device *dev) { void __iomem *ioaddr = hw->pcsr; - u32 value = readl(ioaddr + GMAC_CONTROL); int mtu = dev->mtu; + u32 value; /* Configure GMAC core */ - value |= GMAC_CORE_INIT; + value = readl(ioaddr + GMAC_CONTROL); if (mtu > 1500) value |= GMAC_CONTROL_2K; if (mtu > 2000) value |= GMAC_CONTROL_JE; - if (hw->ps) { - value |= GMAC_CONTROL_TE; - - value &= ~hw->link.speed_mask; - switch (hw->ps) { - case SPEED_1000: - value |= hw->link.speed1000; - break; - case SPEED_100: - value |= hw->link.speed100; - break; - case SPEED_10: - value |= hw->link.speed10; - break; - } - } - - writel(value, ioaddr + GMAC_CONTROL); + writel(value | GMAC_CORE_INIT, ioaddr + GMAC_CONTROL); /* Mask GMAC interrupts */ - value = GMAC_INT_DEFAULT_MASK; - - if (hw->pcs) - value &= ~GMAC_INT_DISABLE_PCS; - - writel(value, ioaddr + GMAC_INT_MASK); + writel(GMAC_INT_DEFAULT_MASK, ioaddr + GMAC_INT_MASK); #ifdef STMMAC_VLAN_TAG_USED /* Tag detection without filtering */ @@ -70,6 +58,20 @@ static void dwmac1000_core_init(struct mac_device_info *hw, #endif } +static void dwmac1000_irq_modify(struct mac_device_info *hw, u32 disable, + u32 enable) +{ + void __iomem *int_mask = hw->pcsr + GMAC_INT_MASK; + unsigned long flags; + u32 value; + + spin_lock_irqsave(&hw->irq_ctrl_lock, flags); + value = readl(int_mask) | disable; + value &= ~enable; + writel(value, int_mask); + spin_unlock_irqrestore(&hw->irq_ctrl_lock, flags); +} + static int dwmac1000_rx_ipc_enable(struct mac_device_info *hw) { void __iomem *ioaddr = hw->pcsr; @@ -263,39 +265,6 @@ static void dwmac1000_pmt(struct mac_device_info *hw, unsigned long mode) writel(pmt, ioaddr + GMAC_PMT); } -/* RGMII or SMII interface */ -static void dwmac1000_rgsmii(void __iomem *ioaddr, struct stmmac_extra_stats *x) -{ - u32 status; - - status = readl(ioaddr + GMAC_RGSMIIIS); - x->irq_rgmii_n++; - - /* Check the link status */ - if (status & GMAC_RGSMIIIS_LNKSTS) { - int speed_value; - - x->pcs_link = 1; - - speed_value = ((status & GMAC_RGSMIIIS_SPEED) >> - GMAC_RGSMIIIS_SPEED_SHIFT); - if (speed_value == GMAC_RGSMIIIS_SPEED_125) - x->pcs_speed = SPEED_1000; - else if (speed_value == GMAC_RGSMIIIS_SPEED_25) - x->pcs_speed = SPEED_100; - else - x->pcs_speed = SPEED_10; - - x->pcs_duplex = (status & GMAC_RGSMIIIS_LNKMOD_MASK); - - pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed, - x->pcs_duplex ? "Full" : "Half"); - } else { - x->pcs_link = 0; - pr_info("Link is Down\n"); - } -} - static int dwmac1000_irq_status(struct mac_device_info *hw, struct stmmac_extra_stats *x) { @@ -337,9 +306,6 @@ static int dwmac1000_irq_status(struct mac_device_info *hw, dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x); - if (intr_status & PCS_RGSMIIIS_IRQ) - dwmac1000_rgsmii(ioaddr, x); - return ret; } @@ -393,15 +359,10 @@ static void dwmac1000_set_eee_timer(struct mac_device_info *hw, int ls, int tw) writel(value, ioaddr + LPI_TIMER_CTRL); } -static void dwmac1000_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral, - bool loopback) -{ - dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback); -} - -static void dwmac1000_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv) +static void dwmac1000_ctrl_ane(struct stmmac_priv *priv, bool ane, + bool srgmi_ral) { - dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv); + dwmac_ctrl_ane(priv->ioaddr, GMAC_PCS_BASE, ane, srgmi_ral); } static void dwmac1000_debug(struct stmmac_priv *priv, void __iomem *ioaddr, @@ -493,7 +454,9 @@ static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable) } const struct stmmac_ops dwmac1000_ops = { + .pcs_init = dwmac1000_pcs_init, .core_init = dwmac1000_core_init, + .irq_modify = dwmac1000_irq_modify, .set_mac = stmmac_set_mac, .rx_ipc = dwmac1000_rx_ipc_enable, .dump_regs = dwmac1000_dump_regs, @@ -508,7 +471,6 @@ const struct stmmac_ops dwmac1000_ops = { .set_eee_pls = dwmac1000_set_eee_pls, .debug = dwmac1000_debug, .pcs_ctrl_ane = dwmac1000_ctrl_ane, - .pcs_get_adv_lp = dwmac1000_get_adv_lp, .set_mac_loopback = dwmac1000_set_mac_loopback, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index 118a22406a2e..5877fec9f6c3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -19,7 +19,6 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) { u32 value = readl(ioaddr + DMA_AXI_BUS_MODE); - int i; pr_info("dwmac1000: Master AXI performs %s burst length\n", !(value & DMA_AXI_UNDEF) ? "fixed" : "any"); @@ -39,33 +38,10 @@ static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) /* Depending on the UNDEF bit the Master AXI will perform any burst * length according to the BLEN programmed (by default all BLEN are - * set). + * set). Note that the UNDEF bit is readonly, and is the inverse of + * Bus Mode bit 16. */ - for (i = 0; i < AXI_BLEN; i++) { - switch (axi->axi_blen[i]) { - case 256: - value |= DMA_AXI_BLEN256; - break; - case 128: - value |= DMA_AXI_BLEN128; - break; - case 64: - value |= DMA_AXI_BLEN64; - break; - case 32: - value |= DMA_AXI_BLEN32; - break; - case 16: - value |= DMA_AXI_BLEN16; - break; - case 8: - value |= DMA_AXI_BLEN8; - break; - case 4: - value |= DMA_AXI_BLEN4; - break; - } - } + value = (value & ~DMA_AXI_BLEN_MASK) | axi->axi_blen_regval; writel(value, ioaddr + DMA_AXI_BUS_MODE); } @@ -159,10 +135,10 @@ static void dwmac1000_dma_operation_mode_rx(struct stmmac_priv *priv, if (mode == SF_DMA_MODE) { pr_debug("GMAC: enable RX store and forward mode\n"); - csr6 |= DMA_CONTROL_RSF; + csr6 |= DMA_CONTROL_RSF | DMA_CONTROL_DFF; } else { pr_debug("GMAC: disable RX SF mode (threshold %d)\n", mode); - csr6 &= ~DMA_CONTROL_RSF; + csr6 &= ~(DMA_CONTROL_RSF | DMA_CONTROL_DFF); csr6 &= DMA_CONTROL_TC_RX_MASK; if (mode <= 32) csr6 |= DMA_CONTROL_RTC_32; @@ -286,6 +262,7 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = { .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_reception = dwmac_enable_dma_reception, .enable_dma_irq = dwmac_enable_dma_irq, .disable_dma_irq = dwmac_disable_dma_irq, .start_tx = dwmac_dma_start_tx, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 42fe29a4e300..3cb733781e1e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -17,11 +17,7 @@ #define GMAC_EXT_CONFIG 0x00000004 #define GMAC_PACKET_FILTER 0x00000008 #define GMAC_HASH_TAB(x) (0x10 + (x) * 4) -#define GMAC_VLAN_TAG 0x00000050 -#define GMAC_VLAN_TAG_DATA 0x00000054 -#define GMAC_VLAN_HASH_TABLE 0x00000058 #define GMAC_RX_FLOW_CTRL 0x00000090 -#define GMAC_VLAN_INCL 0x00000060 #define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4) #define GMAC_TXQ_PRTY_MAP0 0x98 #define GMAC_TXQ_PRTY_MAP1 0x9C @@ -31,7 +27,6 @@ #define GMAC_RXQ_CTRL3 0x000000ac #define GMAC_INT_STATUS 0x000000b0 #define GMAC_INT_EN 0x000000b4 -#define GMAC_1US_TIC_COUNTER 0x000000dc #define GMAC_PCS_BASE 0x000000e0 #define GMAC_PHYIF_CONTROL_STATUS 0x000000f8 #define GMAC_PMT 0x000000c0 @@ -82,42 +77,6 @@ #define GMAC_MAX_PERFECT_ADDRESSES 128 -/* MAC VLAN */ -#define GMAC_VLAN_EDVLP BIT(26) -#define GMAC_VLAN_VTHM BIT(25) -#define GMAC_VLAN_DOVLTC BIT(20) -#define GMAC_VLAN_ESVL BIT(18) -#define GMAC_VLAN_ETV BIT(16) -#define GMAC_VLAN_VID GENMASK(15, 0) -#define GMAC_VLAN_VLTI BIT(20) -#define GMAC_VLAN_CSVL BIT(19) -#define GMAC_VLAN_VLC GENMASK(17, 16) -#define GMAC_VLAN_VLC_SHIFT 16 -#define GMAC_VLAN_VLHT GENMASK(15, 0) - -/* MAC VLAN Tag */ -#define GMAC_VLAN_TAG_VID GENMASK(15, 0) -#define GMAC_VLAN_TAG_ETV BIT(16) - -/* MAC VLAN Tag Control */ -#define GMAC_VLAN_TAG_CTRL_OB BIT(0) -#define GMAC_VLAN_TAG_CTRL_CT BIT(1) -#define GMAC_VLAN_TAG_CTRL_OFS_MASK GENMASK(6, 2) -#define GMAC_VLAN_TAG_CTRL_OFS_SHIFT 2 -#define GMAC_VLAN_TAG_CTRL_EVLS_MASK GENMASK(22, 21) -#define GMAC_VLAN_TAG_CTRL_EVLS_SHIFT 21 -#define GMAC_VLAN_TAG_CTRL_EVLRXS BIT(24) - -#define GMAC_VLAN_TAG_STRIP_NONE (0x0 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) -#define GMAC_VLAN_TAG_STRIP_PASS (0x1 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) -#define GMAC_VLAN_TAG_STRIP_FAIL (0x2 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) -#define GMAC_VLAN_TAG_STRIP_ALL (0x3 << GMAC_VLAN_TAG_CTRL_EVLS_SHIFT) - -/* MAC VLAN Tag Data/Filter */ -#define GMAC_VLAN_TAG_DATA_VID GENMASK(15, 0) -#define GMAC_VLAN_TAG_DATA_VEN BIT(16) -#define GMAC_VLAN_TAG_DATA_ETV BIT(17) - /* MAC RX Queue Enable */ #define GMAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2)) #define GMAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2) @@ -147,9 +106,6 @@ #define GMAC_INT_LPI_EN BIT(5) #define GMAC_INT_TSIE BIT(12) -#define GMAC_PCS_IRQ_DEFAULT (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \ - GMAC_INT_PCS_ANE) - #define GMAC_INT_DEFAULT_ENABLE (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN | \ GMAC_INT_TSIE) @@ -382,6 +338,7 @@ static inline u32 mtl_chanx_base_addr(const struct dwmac4_addrs *addrs, #define MTL_OP_MODE_RFA_SHIFT 8 #define MTL_OP_MODE_EHFC BIT(7) +#define MTL_OP_MODE_DIS_TCP_EF BIT(6) #define MTL_OP_MODE_RTC_MASK GENMASK(1, 0) #define MTL_OP_MODE_RTC_SHIFT 0 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index cc4ddf608652..a4282fd7c3c7 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -18,54 +18,55 @@ #include "stmmac.h" #include "stmmac_fpe.h" #include "stmmac_pcs.h" +#include "stmmac_vlan.h" #include "dwmac4.h" #include "dwmac5.h" +static int dwmac4_pcs_init(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.pcs) + return 0; + + return stmmac_integrated_pcs_init(priv, GMAC_PCS_BASE, + GMAC_INT_PCS_LINK | GMAC_INT_PCS_ANE); +} + static void dwmac4_core_init(struct mac_device_info *hw, struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); void __iomem *ioaddr = hw->pcsr; - u32 value = readl(ioaddr + GMAC_CONFIG); unsigned long clk_rate; + u32 value; - value |= GMAC_CORE_INIT; - - if (hw->ps) { - value |= GMAC_CONFIG_TE; - - value &= hw->link.speed_mask; - switch (hw->ps) { - case SPEED_1000: - value |= hw->link.speed1000; - break; - case SPEED_100: - value |= hw->link.speed100; - break; - case SPEED_10: - value |= hw->link.speed10; - break; - } - } - - writel(value, ioaddr + GMAC_CONFIG); + value = readl(ioaddr + GMAC_CONFIG); + writel(value | GMAC_CORE_INIT, ioaddr + GMAC_CONFIG); /* Configure LPI 1us counter to number of CSR clock ticks in 1us - 1 */ clk_rate = clk_get_rate(priv->plat->stmmac_clk); writel((clk_rate / 1000000) - 1, ioaddr + GMAC4_MAC_ONEUS_TIC_COUNTER); /* Enable GMAC interrupts */ - value = GMAC_INT_DEFAULT_ENABLE; - - if (hw->pcs) - value |= GMAC_PCS_IRQ_DEFAULT; - - writel(value, ioaddr + GMAC_INT_EN); + writel(GMAC_INT_DEFAULT_ENABLE, ioaddr + GMAC_INT_EN); if (GMAC_INT_DEFAULT_ENABLE & GMAC_INT_TSIE) init_waitqueue_head(&priv->tstamp_busy_wait); } +static void dwmac4_irq_modify(struct mac_device_info *hw, u32 disable, + u32 enable) +{ + void __iomem *int_mask = hw->pcsr + GMAC_INT_EN; + unsigned long flags; + u32 value; + + spin_lock_irqsave(&hw->irq_ctrl_lock, flags); + value = readl(int_mask) & ~disable; + value |= enable; + writel(value, int_mask); + spin_unlock_irqrestore(&hw->irq_ctrl_lock, flags); +} + static void dwmac4_update_caps(struct stmmac_priv *priv) { if (priv->plat->tx_queues_to_use > 1) @@ -448,165 +449,6 @@ static void dwmac4_set_eee_timer(struct mac_device_info *hw, int ls, int tw) writel(value, ioaddr + GMAC4_LPI_TIMER_CTRL); } -static void dwmac4_write_single_vlan(struct net_device *dev, u16 vid) -{ - void __iomem *ioaddr = (void __iomem *)dev->base_addr; - u32 val; - - val = readl(ioaddr + GMAC_VLAN_TAG); - val &= ~GMAC_VLAN_TAG_VID; - val |= GMAC_VLAN_TAG_ETV | vid; - - writel(val, ioaddr + GMAC_VLAN_TAG); -} - -static int dwmac4_write_vlan_filter(struct net_device *dev, - struct mac_device_info *hw, - u8 index, u32 data) -{ - void __iomem *ioaddr = (void __iomem *)dev->base_addr; - int ret; - u32 val; - - if (index >= hw->num_vlan) - return -EINVAL; - - writel(data, ioaddr + GMAC_VLAN_TAG_DATA); - - val = readl(ioaddr + GMAC_VLAN_TAG); - val &= ~(GMAC_VLAN_TAG_CTRL_OFS_MASK | - GMAC_VLAN_TAG_CTRL_CT | - GMAC_VLAN_TAG_CTRL_OB); - val |= (index << GMAC_VLAN_TAG_CTRL_OFS_SHIFT) | GMAC_VLAN_TAG_CTRL_OB; - - writel(val, ioaddr + GMAC_VLAN_TAG); - - ret = readl_poll_timeout(ioaddr + GMAC_VLAN_TAG, val, - !(val & GMAC_VLAN_TAG_CTRL_OB), - 1000, 500000); - if (ret) { - netdev_err(dev, "Timeout accessing MAC_VLAN_Tag_Filter\n"); - return -EBUSY; - } - - return 0; -} - -static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev, - struct mac_device_info *hw, - __be16 proto, u16 vid) -{ - int index = -1; - u32 val = 0; - int i, ret; - - if (vid > 4095) - return -EINVAL; - - /* Single Rx VLAN Filter */ - if (hw->num_vlan == 1) { - /* For single VLAN filter, VID 0 means VLAN promiscuous */ - if (vid == 0) { - netdev_warn(dev, "Adding VLAN ID 0 is not supported\n"); - return -EPERM; - } - - if (hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) { - netdev_err(dev, "Only single VLAN ID supported\n"); - return -EPERM; - } - - hw->vlan_filter[0] = vid; - dwmac4_write_single_vlan(dev, vid); - - return 0; - } - - /* Extended Rx VLAN Filter Enable */ - val |= GMAC_VLAN_TAG_DATA_ETV | GMAC_VLAN_TAG_DATA_VEN | vid; - - for (i = 0; i < hw->num_vlan; i++) { - if (hw->vlan_filter[i] == val) - return 0; - else if (!(hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN)) - index = i; - } - - if (index == -1) { - netdev_err(dev, "MAC_VLAN_Tag_Filter full (size: %0u)\n", - hw->num_vlan); - return -EPERM; - } - - ret = dwmac4_write_vlan_filter(dev, hw, index, val); - - if (!ret) - hw->vlan_filter[index] = val; - - return ret; -} - -static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev, - struct mac_device_info *hw, - __be16 proto, u16 vid) -{ - int i, ret = 0; - - /* Single Rx VLAN Filter */ - if (hw->num_vlan == 1) { - if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) { - hw->vlan_filter[0] = 0; - dwmac4_write_single_vlan(dev, 0); - } - return 0; - } - - /* Extended Rx VLAN Filter Enable */ - for (i = 0; i < hw->num_vlan; i++) { - if ((hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VID) == vid) { - ret = dwmac4_write_vlan_filter(dev, hw, i, 0); - - if (!ret) - hw->vlan_filter[i] = 0; - else - return ret; - } - } - - return ret; -} - -static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev, - struct mac_device_info *hw) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - u32 hash; - u32 val; - int i; - - /* Single Rx VLAN Filter */ - if (hw->num_vlan == 1) { - dwmac4_write_single_vlan(dev, hw->vlan_filter[0]); - return; - } - - /* Extended Rx VLAN Filter Enable */ - for (i = 0; i < hw->num_vlan; i++) { - if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) { - val = hw->vlan_filter[i]; - dwmac4_write_vlan_filter(dev, hw, i, val); - } - } - - hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); - if (hash & GMAC_VLAN_VLHT) { - value = readl(ioaddr + GMAC_VLAN_TAG); - value |= GMAC_VLAN_VTHM; - writel(value, ioaddr + GMAC_VLAN_TAG); - } -} - static void dwmac4_set_filter(struct mac_device_info *hw, struct net_device *dev) { @@ -741,48 +583,9 @@ static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, } } -static void dwmac4_ctrl_ane(void __iomem *ioaddr, bool ane, bool srgmi_ral, - bool loopback) +static void dwmac4_ctrl_ane(struct stmmac_priv *priv, bool ane, bool srgmi_ral) { - dwmac_ctrl_ane(ioaddr, GMAC_PCS_BASE, ane, srgmi_ral, loopback); -} - -static void dwmac4_get_adv_lp(void __iomem *ioaddr, struct rgmii_adv *adv) -{ - dwmac_get_adv_lp(ioaddr, GMAC_PCS_BASE, adv); -} - -/* RGMII or SMII interface */ -static void dwmac4_phystatus(void __iomem *ioaddr, struct stmmac_extra_stats *x) -{ - u32 status; - - status = readl(ioaddr + GMAC_PHYIF_CONTROL_STATUS); - x->irq_rgmii_n++; - - /* Check the link status */ - if (status & GMAC_PHYIF_CTRLSTATUS_LNKSTS) { - int speed_value; - - x->pcs_link = 1; - - speed_value = ((status & GMAC_PHYIF_CTRLSTATUS_SPEED) >> - GMAC_PHYIF_CTRLSTATUS_SPEED_SHIFT); - if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_125) - x->pcs_speed = SPEED_1000; - else if (speed_value == GMAC_PHYIF_CTRLSTATUS_SPEED_25) - x->pcs_speed = SPEED_100; - else - x->pcs_speed = SPEED_10; - - x->pcs_duplex = (status & GMAC_PHYIF_CTRLSTATUS_LNKMOD); - - pr_info("Link is Up - %d/%s\n", (int)x->pcs_speed, - x->pcs_duplex ? "Full" : "Half"); - } else { - x->pcs_link = 0; - pr_info("Link is Down\n"); - } + dwmac_ctrl_ane(priv->ioaddr, GMAC_PCS_BASE, ane, srgmi_ral); } static int dwmac4_irq_mtl_status(struct stmmac_priv *priv, @@ -856,8 +659,6 @@ static int dwmac4_irq_status(struct mac_device_info *hw, } dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x); - if (intr_status & PCS_RGSMIIIS_IRQ) - dwmac4_phystatus(ioaddr, x); return ret; } @@ -965,45 +766,6 @@ static void dwmac4_set_mac_loopback(void __iomem *ioaddr, bool enable) writel(value, ioaddr + GMAC_CONFIG); } -static void dwmac4_update_vlan_hash(struct mac_device_info *hw, u32 hash, - u16 perfect_match, bool is_double) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - - writel(hash, ioaddr + GMAC_VLAN_HASH_TABLE); - - value = readl(ioaddr + GMAC_VLAN_TAG); - - if (hash) { - value |= GMAC_VLAN_VTHM | GMAC_VLAN_ETV; - if (is_double) { - value |= GMAC_VLAN_EDVLP; - value |= GMAC_VLAN_ESVL; - value |= GMAC_VLAN_DOVLTC; - } - - writel(value, ioaddr + GMAC_VLAN_TAG); - } else if (perfect_match) { - u32 value = GMAC_VLAN_ETV; - - if (is_double) { - value |= GMAC_VLAN_EDVLP; - value |= GMAC_VLAN_ESVL; - value |= GMAC_VLAN_DOVLTC; - } - - writel(value | perfect_match, ioaddr + GMAC_VLAN_TAG); - } else { - value &= ~(GMAC_VLAN_VTHM | GMAC_VLAN_ETV); - value &= ~(GMAC_VLAN_EDVLP | GMAC_VLAN_ESVL); - value &= ~GMAC_VLAN_DOVLTC; - value &= ~GMAC_VLAN_VID; - - writel(value, ioaddr + GMAC_VLAN_TAG); - } -} - static void dwmac4_sarc_configure(void __iomem *ioaddr, int val) { u32 value = readl(ioaddr + GMAC_CONFIG); @@ -1014,19 +776,6 @@ static void dwmac4_sarc_configure(void __iomem *ioaddr, int val) writel(value, ioaddr + GMAC_CONFIG); } -static void dwmac4_enable_vlan(struct mac_device_info *hw, u32 type) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - - value = readl(ioaddr + GMAC_VLAN_INCL); - value |= GMAC_VLAN_VLTI; - value |= GMAC_VLAN_CSVL; /* Only use SVLAN */ - value &= ~GMAC_VLAN_VLC; - value |= (type << GMAC_VLAN_VLC_SHIFT) & GMAC_VLAN_VLC; - writel(value, ioaddr + GMAC_VLAN_INCL); -} - static void dwmac4_set_arp_offload(struct mac_device_info *hw, bool en, u32 addr) { @@ -1143,37 +892,10 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no, return 0; } -static void dwmac4_rx_hw_vlan(struct mac_device_info *hw, - struct dma_desc *rx_desc, struct sk_buff *skb) -{ - if (hw->desc->get_rx_vlan_valid(rx_desc)) { - u16 vid = hw->desc->get_rx_vlan_tci(rx_desc); - - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); - } -} - -static void dwmac4_set_hw_vlan_mode(struct mac_device_info *hw) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value = readl(ioaddr + GMAC_VLAN_TAG); - - value &= ~GMAC_VLAN_TAG_CTRL_EVLS_MASK; - - if (hw->hw_vlan_en) - /* Always strip VLAN on Receive */ - value |= GMAC_VLAN_TAG_STRIP_ALL; - else - /* Do not strip VLAN on Receive */ - value |= GMAC_VLAN_TAG_STRIP_NONE; - - /* Enable outer VLAN Tag in Rx DMA descriptor */ - value |= GMAC_VLAN_TAG_CTRL_EVLRXS; - writel(value, ioaddr + GMAC_VLAN_TAG); -} - const struct stmmac_ops dwmac4_ops = { + .pcs_init = dwmac4_pcs_init, .core_init = dwmac4_core_init, + .irq_modify = dwmac4_irq_modify, .update_caps = dwmac4_update_caps, .set_mac = stmmac_set_mac, .rx_ipc = dwmac4_rx_ipc_enable, @@ -1197,25 +919,19 @@ const struct stmmac_ops dwmac4_ops = { .set_eee_timer = dwmac4_set_eee_timer, .set_eee_pls = dwmac4_set_eee_pls, .pcs_ctrl_ane = dwmac4_ctrl_ane, - .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, .set_mac_loopback = dwmac4_set_mac_loopback, - .update_vlan_hash = dwmac4_update_vlan_hash, .sarc_configure = dwmac4_sarc_configure, - .enable_vlan = dwmac4_enable_vlan, .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, - .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, - .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, - .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, - .rx_hw_vlan = dwmac4_rx_hw_vlan, - .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode, }; const struct stmmac_ops dwmac410_ops = { + .pcs_init = dwmac4_pcs_init, .core_init = dwmac4_core_init, + .irq_modify = dwmac4_irq_modify, .update_caps = dwmac4_update_caps, .set_mac = stmmac_dwmac4_set_mac, .rx_ipc = dwmac4_rx_ipc_enable, @@ -1239,27 +955,21 @@ const struct stmmac_ops dwmac410_ops = { .set_eee_timer = dwmac4_set_eee_timer, .set_eee_pls = dwmac4_set_eee_pls, .pcs_ctrl_ane = dwmac4_ctrl_ane, - .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, .flex_pps_config = dwmac5_flex_pps_config, .set_mac_loopback = dwmac4_set_mac_loopback, - .update_vlan_hash = dwmac4_update_vlan_hash, .sarc_configure = dwmac4_sarc_configure, - .enable_vlan = dwmac4_enable_vlan, .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, .fpe_map_preemption_class = dwmac5_fpe_map_preemption_class, - .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, - .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, - .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, - .rx_hw_vlan = dwmac4_rx_hw_vlan, - .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode, }; const struct stmmac_ops dwmac510_ops = { + .pcs_init = dwmac4_pcs_init, .core_init = dwmac4_core_init, + .irq_modify = dwmac4_irq_modify, .update_caps = dwmac4_update_caps, .set_mac = stmmac_dwmac4_set_mac, .rx_ipc = dwmac4_rx_ipc_enable, @@ -1283,7 +993,6 @@ const struct stmmac_ops dwmac510_ops = { .set_eee_timer = dwmac4_set_eee_timer, .set_eee_pls = dwmac4_set_eee_pls, .pcs_ctrl_ane = dwmac4_ctrl_ane, - .pcs_get_adv_lp = dwmac4_get_adv_lp, .debug = dwmac4_debug, .set_filter = dwmac4_set_filter, .safety_feat_config = dwmac5_safety_feat_config, @@ -1292,51 +1001,13 @@ const struct stmmac_ops dwmac510_ops = { .rxp_config = dwmac5_rxp_config, .flex_pps_config = dwmac5_flex_pps_config, .set_mac_loopback = dwmac4_set_mac_loopback, - .update_vlan_hash = dwmac4_update_vlan_hash, .sarc_configure = dwmac4_sarc_configure, - .enable_vlan = dwmac4_enable_vlan, .set_arp_offload = dwmac4_set_arp_offload, .config_l3_filter = dwmac4_config_l3_filter, .config_l4_filter = dwmac4_config_l4_filter, .fpe_map_preemption_class = dwmac5_fpe_map_preemption_class, - .add_hw_vlan_rx_fltr = dwmac4_add_hw_vlan_rx_fltr, - .del_hw_vlan_rx_fltr = dwmac4_del_hw_vlan_rx_fltr, - .restore_hw_vlan_rx_fltr = dwmac4_restore_hw_vlan_rx_fltr, - .rx_hw_vlan = dwmac4_rx_hw_vlan, - .set_hw_vlan_mode = dwmac4_set_hw_vlan_mode, }; -static u32 dwmac4_get_num_vlan(void __iomem *ioaddr) -{ - u32 val, num_vlan; - - val = readl(ioaddr + GMAC_HW_FEATURE3); - switch (val & GMAC_HW_FEAT_NRVF) { - case 0: - num_vlan = 1; - break; - case 1: - num_vlan = 4; - break; - case 2: - num_vlan = 8; - break; - case 3: - num_vlan = 16; - break; - case 4: - num_vlan = 24; - break; - case 5: - num_vlan = 32; - break; - default: - num_vlan = 1; - } - - return num_vlan; -} - int dwmac4_setup(struct stmmac_priv *priv) { struct mac_device_info *mac = priv->hw; @@ -1368,7 +1039,7 @@ int dwmac4_setup(struct stmmac_priv *priv) mac->mii.reg_mask = GENMASK(20, 16); mac->mii.clk_csr_shift = 8; mac->mii.clk_csr_mask = GENMASK(11, 8); - mac->num_vlan = dwmac4_get_num_vlan(priv->ioaddr); + mac->num_vlan = stmmac_get_num_vlan(priv->ioaddr); return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index a5fb31eb0192..aac68dc28dc1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -110,16 +110,20 @@ static int dwmac4_wrback_get_rx_status(struct stmmac_extra_stats *x, message_type = (rdes1 & ERDES4_MSG_TYPE_MASK) >> 8; - if (rdes1 & RDES1_IP_HDR_ERROR) + if (rdes1 & RDES1_IP_HDR_ERROR) { x->ip_hdr_err++; + ret |= csum_none; + } if (rdes1 & RDES1_IP_CSUM_BYPASSED) x->ip_csum_bypassed++; if (rdes1 & RDES1_IPV4_HEADER) x->ipv4_pkt_rcvd++; if (rdes1 & RDES1_IPV6_HEADER) x->ipv6_pkt_rcvd++; - if (rdes1 & RDES1_IP_PAYLOAD_ERROR) + if (rdes1 & RDES1_IP_PAYLOAD_ERROR) { x->ip_payload_err++; + ret |= csum_none; + } if (message_type == RDES_EXT_NO_PTP) x->no_ptp_rx_msg_type_ext++; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c index 0cb84a0041a4..7b513324cfb0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c @@ -18,7 +18,6 @@ static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) { u32 value = readl(ioaddr + DMA_SYS_BUS_MODE); - int i; pr_info("dwmac4: Master AXI performs %s burst length\n", (value & DMA_SYS_BUS_FB) ? "fixed" : "any"); @@ -38,33 +37,10 @@ static void dwmac4_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) /* Depending on the UNDEF bit the Master AXI will perform any burst * length according to the BLEN programmed (by default all BLEN are - * set). + * set). Note that the UNDEF bit is readonly, and is the inverse of + * Bus Mode bit 16. */ - for (i = 0; i < AXI_BLEN; i++) { - switch (axi->axi_blen[i]) { - case 256: - value |= DMA_AXI_BLEN256; - break; - case 128: - value |= DMA_AXI_BLEN128; - break; - case 64: - value |= DMA_AXI_BLEN64; - break; - case 32: - value |= DMA_AXI_BLEN32; - break; - case 16: - value |= DMA_AXI_BLEN16; - break; - case 8: - value |= DMA_AXI_BLEN8; - break; - case 4: - value |= DMA_AXI_BLEN4; - break; - } - } + value = (value & ~DMA_AXI_BLEN_MASK) | axi->axi_blen_regval; writel(value, ioaddr + DMA_SYS_BUS_MODE); } @@ -268,6 +244,8 @@ static void dwmac4_dma_rx_chan_op_mode(struct stmmac_priv *priv, mtl_rx_op = readl(ioaddr + MTL_CHAN_RX_OP_MODE(dwmac4_addrs, channel)); + mtl_rx_op |= MTL_OP_MODE_DIS_TCP_EF; + if (mode == SF_DMA_MODE) { pr_debug("GMAC: enable RX store and forward mode\n"); mtl_rx_op |= MTL_OP_MODE_RSF; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h index 4f980dcd3958..f27126f05551 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.h @@ -69,15 +69,8 @@ #define DMA_SYS_BUS_MB BIT(14) #define DMA_AXI_1KBBE BIT(13) -#define DMA_SYS_BUS_AAL BIT(12) +#define DMA_SYS_BUS_AAL DMA_AXI_AAL #define DMA_SYS_BUS_EAME BIT(11) -#define DMA_AXI_BLEN256 BIT(7) -#define DMA_AXI_BLEN128 BIT(6) -#define DMA_AXI_BLEN64 BIT(5) -#define DMA_AXI_BLEN32 BIT(4) -#define DMA_AXI_BLEN16 BIT(3) -#define DMA_AXI_BLEN8 BIT(2) -#define DMA_AXI_BLEN4 BIT(1) #define DMA_SYS_BUS_FB BIT(0) #define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \ @@ -85,8 +78,6 @@ DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \ DMA_AXI_BLEN4) -#define DMA_AXI_BURST_LEN_MASK 0x000000FE - /* DMA TBS Control */ #define DMA_TBS_FTOS GENMASK(31, 8) #define DMA_TBS_FTOV BIT(0) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h index 5d9c18f5bbf5..054ecb20ce3f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h @@ -68,23 +68,14 @@ static inline u32 dma_chan_base_addr(u32 base, u32 chan) #define DMA_AXI_OSR_MAX 0xf #define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \ (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT)) -#define DMA_AXI_1KBBE BIT(13) -#define DMA_AXI_AAL BIT(12) -#define DMA_AXI_BLEN256 BIT(7) -#define DMA_AXI_BLEN128 BIT(6) -#define DMA_AXI_BLEN64 BIT(5) -#define DMA_AXI_BLEN32 BIT(4) -#define DMA_AXI_BLEN16 BIT(3) -#define DMA_AXI_BLEN8 BIT(2) -#define DMA_AXI_BLEN4 BIT(1) #define DMA_BURST_LEN_DEFAULT (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \ DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \ DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \ DMA_AXI_BLEN4) -#define DMA_AXI_UNDEF BIT(0) +#define DMA_AXI_1KBBE BIT(13) -#define DMA_AXI_BURST_LEN_MASK 0x000000FE +#define DMA_AXI_UNDEF BIT(0) #define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ #define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ @@ -178,6 +169,7 @@ static inline u32 dma_chan_base_addr(u32 base, u32 chan) #define NUM_DWMAC4_DMA_REGS 27 void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan); +void dwmac_enable_dma_reception(void __iomem *ioaddr, u32 chan); void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan, bool rx, bool tx); void dwmac_disable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index 4846bf49c576..97a803d68e3a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -33,6 +33,11 @@ void dwmac_enable_dma_transmission(void __iomem *ioaddr, u32 chan) writel(1, ioaddr + DMA_CHAN_XMT_POLL_DEMAND(chan)); } +void dwmac_enable_dma_reception(void __iomem *ioaddr, u32 chan) +{ + writel(1, ioaddr + DMA_CHAN_RCV_POLL_DEMAND(chan)); +} + void dwmac_enable_dma_irq(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan, bool rx, bool tx) { @@ -251,7 +256,7 @@ void dwmac_dma_flush_tx_fifo(void __iomem *ioaddr) void stmmac_set_mac_addr(void __iomem *ioaddr, const u8 addr[6], unsigned int high, unsigned int low) { - unsigned long data; + u32 data; data = (addr[5] << 8) | addr[4]; /* For MAC Addr registers we have to set the Address Enable (AE) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index a03f5d771566..fecda3034d36 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -57,19 +57,6 @@ #define XGMAC_FILTER_PR BIT(0) #define XGMAC_HASH_TABLE(x) (0x00000010 + (x) * 4) #define XGMAC_MAX_HASH_TABLE 8 -#define XGMAC_VLAN_TAG 0x00000050 -#define XGMAC_VLAN_EDVLP BIT(26) -#define XGMAC_VLAN_VTHM BIT(25) -#define XGMAC_VLAN_DOVLTC BIT(20) -#define XGMAC_VLAN_ESVL BIT(18) -#define XGMAC_VLAN_ETV BIT(16) -#define XGMAC_VLAN_VID GENMASK(15, 0) -#define XGMAC_VLAN_HASH_TABLE 0x00000058 -#define XGMAC_VLAN_INCL 0x00000060 -#define XGMAC_VLAN_VLTI BIT(20) -#define XGMAC_VLAN_CSVL BIT(19) -#define XGMAC_VLAN_VLC GENMASK(17, 16) -#define XGMAC_VLAN_VLC_SHIFT 16 #define XGMAC_RXQ_CTRL0 0x000000a0 #define XGMAC_RXQEN(x) GENMASK((x) * 2 + 1, (x) * 2) #define XGMAC_RXQEN_SHIFT(x) ((x) * 2) @@ -92,6 +79,7 @@ #define XGMAC_PSRQ(x) GENMASK((x) * 8 + 7, (x) * 8) #define XGMAC_PSRQ_SHIFT(x) ((x) * 8) #define XGMAC_INT_STATUS 0x000000b0 +#define XGMAC_INT_TSIS BIT(12) #define XGMAC_LPIIS BIT(5) #define XGMAC_PMTIS BIT(4) #define XGMAC_INT_EN 0x000000b4 @@ -186,6 +174,8 @@ #define XGMAC_MDIO_ADDR 0x00000200 #define XGMAC_MDIO_DATA 0x00000204 #define XGMAC_MDIO_C22P 0x00000220 +#define XGMAC_GPIO_STATUS 0x0000027c +#define XGMAC_GPIO_GPO0 BIT(16) #define XGMAC_ADDRx_HIGH(x) (0x00000300 + (x) * 0x8) #define XGMAC_ADDR_MAX 32 #define XGMAC_AE BIT(31) @@ -233,6 +223,8 @@ #define XGMAC_OB BIT(0) #define XGMAC_RSS_DATA 0x00000c8c #define XGMAC_TIMESTAMP_STATUS 0x00000d20 +#define XGMAC_TIMESTAMP_ATSNS_MASK GENMASK(29, 25) +#define XGMAC_TIMESTAMP_ATSNS_SHIFT 25 #define XGMAC_TXTSC BIT(15) #define XGMAC_TXTIMESTAMP_NSEC 0x00000d30 #define XGMAC_TXTSSTSLO GENMASK(30, 0) @@ -346,16 +338,9 @@ #define XGMAC_RD_OSR_LMT_SHIFT 16 #define XGMAC_EN_LPI BIT(15) #define XGMAC_LPI_XIT_PKT BIT(14) -#define XGMAC_AAL BIT(12) +#define XGMAC_AAL DMA_AXI_AAL #define XGMAC_EAME BIT(11) -#define XGMAC_BLEN GENMASK(7, 1) -#define XGMAC_BLEN256 BIT(7) -#define XGMAC_BLEN128 BIT(6) -#define XGMAC_BLEN64 BIT(5) -#define XGMAC_BLEN32 BIT(4) -#define XGMAC_BLEN16 BIT(3) -#define XGMAC_BLEN8 BIT(2) -#define XGMAC_BLEN4 BIT(1) +/* XGMAC_BLEN* are now defined as DMA_AXI_BLEN* in common.h */ #define XGMAC_UNDEF BIT(0) #define XGMAC_TX_EDMA_CTRL 0x00003040 #define XGMAC_TDPS GENMASK(29, 0) @@ -477,6 +462,7 @@ #define XGMAC_RDES3_RSV BIT(26) #define XGMAC_RDES3_L34T GENMASK(23, 20) #define XGMAC_RDES3_L34T_SHIFT 20 +#define XGMAC_RDES3_ET_LT GENMASK(19, 16) #define XGMAC_L34T_IP4TCP 0x1 #define XGMAC_L34T_IP4UDP 0x2 #define XGMAC_L34T_IP6TCP 0x9 @@ -486,6 +472,17 @@ #define XGMAC_RDES3_TSD BIT(6) #define XGMAC_RDES3_TSA BIT(4) +/* RDES0 (write back format) */ +#define XGMAC_RDES0_VLAN_TAG_MASK GENMASK(15, 0) + +/* Error Type or L2 Type(ET/LT) Field Number */ +#define XGMAC_ET_LT_VLAN_STAG 8 +#define XGMAC_ET_LT_VLAN_CTAG 9 +#define XGMAC_ET_LT_DVLAN_CTAG_CTAG 10 +#define XGMAC_ET_LT_DVLAN_STAG_STAG 11 +#define XGMAC_ET_LT_DVLAN_CTAG_STAG 12 +#define XGMAC_ET_LT_DVLAN_STAG_CTAG 13 + extern const struct stmmac_ops dwxgmac210_ops; extern const struct stmmac_ops dwxlgmac2_ops; extern const struct stmmac_dma_ops dwxgmac210_dma_ops; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index a6d395c6bacd..b40b3ea50e25 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -10,6 +10,7 @@ #include "stmmac.h" #include "stmmac_fpe.h" #include "stmmac_ptp.h" +#include "stmmac_vlan.h" #include "dwxlgmac2.h" #include "dwxgmac2.h" @@ -22,30 +23,31 @@ static void dwxgmac2_core_init(struct mac_device_info *hw, tx = readl(ioaddr + XGMAC_TX_CONFIG); rx = readl(ioaddr + XGMAC_RX_CONFIG); - tx |= XGMAC_CORE_INIT_TX; - rx |= XGMAC_CORE_INIT_RX; + writel(tx | XGMAC_CORE_INIT_TX, ioaddr + XGMAC_TX_CONFIG); + writel(rx | XGMAC_CORE_INIT_RX, ioaddr + XGMAC_RX_CONFIG); + writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN); +} - if (hw->ps) { - tx |= XGMAC_CONFIG_TE; - tx &= ~hw->link.speed_mask; +static void dwxgmac2_irq_modify(struct mac_device_info *hw, u32 disable, + u32 enable) +{ + void __iomem *int_mask = hw->pcsr + XGMAC_INT_EN; + unsigned long flags; + u32 value; - switch (hw->ps) { - case SPEED_10000: - tx |= hw->link.xgmii.speed10000; - break; - case SPEED_2500: - tx |= hw->link.speed2500; - break; - case SPEED_1000: - default: - tx |= hw->link.speed1000; - break; - } - } + spin_lock_irqsave(&hw->irq_ctrl_lock, flags); + value = readl(int_mask) & ~disable; + value |= enable; + writel(value, int_mask); + spin_unlock_irqrestore(&hw->irq_ctrl_lock, flags); +} - writel(tx, ioaddr + XGMAC_TX_CONFIG); - writel(rx, ioaddr + XGMAC_RX_CONFIG); - writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN); +static void dwxgmac2_update_caps(struct stmmac_priv *priv) +{ + if (!priv->dma_cap.mbps_10_100) + priv->hw->link.caps &= ~(MAC_10 | MAC_100); + else if (!priv->dma_cap.half_duplex) + priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD); } static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable) @@ -614,76 +616,6 @@ static int dwxgmac2_rss_configure(struct mac_device_info *hw, return 0; } -static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash, - u16 perfect_match, bool is_double) -{ - void __iomem *ioaddr = hw->pcsr; - - writel(hash, ioaddr + XGMAC_VLAN_HASH_TABLE); - - if (hash) { - u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); - - value |= XGMAC_FILTER_VTFE; - - writel(value, ioaddr + XGMAC_PACKET_FILTER); - - value = readl(ioaddr + XGMAC_VLAN_TAG); - - value |= XGMAC_VLAN_VTHM | XGMAC_VLAN_ETV; - if (is_double) { - value |= XGMAC_VLAN_EDVLP; - value |= XGMAC_VLAN_ESVL; - value |= XGMAC_VLAN_DOVLTC; - } else { - value &= ~XGMAC_VLAN_EDVLP; - value &= ~XGMAC_VLAN_ESVL; - value &= ~XGMAC_VLAN_DOVLTC; - } - - value &= ~XGMAC_VLAN_VID; - writel(value, ioaddr + XGMAC_VLAN_TAG); - } else if (perfect_match) { - u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); - - value |= XGMAC_FILTER_VTFE; - - writel(value, ioaddr + XGMAC_PACKET_FILTER); - - value = readl(ioaddr + XGMAC_VLAN_TAG); - - value &= ~XGMAC_VLAN_VTHM; - value |= XGMAC_VLAN_ETV; - if (is_double) { - value |= XGMAC_VLAN_EDVLP; - value |= XGMAC_VLAN_ESVL; - value |= XGMAC_VLAN_DOVLTC; - } else { - value &= ~XGMAC_VLAN_EDVLP; - value &= ~XGMAC_VLAN_ESVL; - value &= ~XGMAC_VLAN_DOVLTC; - } - - value &= ~XGMAC_VLAN_VID; - writel(value | perfect_match, ioaddr + XGMAC_VLAN_TAG); - } else { - u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); - - value &= ~XGMAC_FILTER_VTFE; - - writel(value, ioaddr + XGMAC_PACKET_FILTER); - - value = readl(ioaddr + XGMAC_VLAN_TAG); - - value &= ~(XGMAC_VLAN_VTHM | XGMAC_VLAN_ETV); - value &= ~(XGMAC_VLAN_EDVLP | XGMAC_VLAN_ESVL); - value &= ~XGMAC_VLAN_DOVLTC; - value &= ~XGMAC_VLAN_VID; - - writel(value, ioaddr + XGMAC_VLAN_TAG); - } -} - struct dwxgmac3_error_desc { bool valid; const char *desc; @@ -1300,19 +1232,6 @@ static void dwxgmac2_sarc_configure(void __iomem *ioaddr, int val) writel(value, ioaddr + XGMAC_TX_CONFIG); } -static void dwxgmac2_enable_vlan(struct mac_device_info *hw, u32 type) -{ - void __iomem *ioaddr = hw->pcsr; - u32 value; - - value = readl(ioaddr + XGMAC_VLAN_INCL); - value |= XGMAC_VLAN_VLTI; - value |= XGMAC_VLAN_CSVL; /* Only use SVLAN */ - value &= ~XGMAC_VLAN_VLC; - value |= (type << XGMAC_VLAN_VLC_SHIFT) & XGMAC_VLAN_VLC; - writel(value, ioaddr + XGMAC_VLAN_INCL); -} - static int dwxgmac2_filter_wait(struct mac_device_info *hw) { void __iomem *ioaddr = hw->pcsr; @@ -1506,6 +1425,8 @@ static void dwxgmac2_set_arp_offload(struct mac_device_info *hw, bool en, const struct stmmac_ops dwxgmac210_ops = { .core_init = dwxgmac2_core_init, + .irq_modify = dwxgmac2_irq_modify, + .update_caps = dwxgmac2_update_caps, .set_mac = dwxgmac2_set_mac, .rx_ipc = dwxgmac2_rx_ipc, .rx_queue_enable = dwxgmac2_rx_queue_enable, @@ -1534,12 +1455,10 @@ const struct stmmac_ops dwxgmac210_ops = { .safety_feat_dump = dwxgmac3_safety_feat_dump, .set_mac_loopback = dwxgmac2_set_mac_loopback, .rss_configure = dwxgmac2_rss_configure, - .update_vlan_hash = dwxgmac2_update_vlan_hash, .rxp_config = dwxgmac3_rxp_config, .get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp, .flex_pps_config = dwxgmac2_flex_pps_config, .sarc_configure = dwxgmac2_sarc_configure, - .enable_vlan = dwxgmac2_enable_vlan, .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, @@ -1562,6 +1481,7 @@ static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode, const struct stmmac_ops dwxlgmac2_ops = { .core_init = dwxgmac2_core_init, + .irq_modify = dwxgmac2_irq_modify, .set_mac = dwxgmac2_set_mac, .rx_ipc = dwxgmac2_rx_ipc, .rx_queue_enable = dwxlgmac2_rx_queue_enable, @@ -1590,12 +1510,10 @@ const struct stmmac_ops dwxlgmac2_ops = { .safety_feat_dump = dwxgmac3_safety_feat_dump, .set_mac_loopback = dwxgmac2_set_mac_loopback, .rss_configure = dwxgmac2_rss_configure, - .update_vlan_hash = dwxgmac2_update_vlan_hash, .rxp_config = dwxgmac3_rxp_config, .get_mac_tx_timestamp = dwxgmac2_get_mac_tx_timestamp, .flex_pps_config = dwxgmac2_flex_pps_config, .sarc_configure = dwxgmac2_sarc_configure, - .enable_vlan = dwxgmac2_enable_vlan, .config_l3_filter = dwxgmac2_config_l3_filter, .config_l4_filter = dwxgmac2_config_l4_filter, .set_arp_offload = dwxgmac2_set_arp_offload, @@ -1618,8 +1536,8 @@ int dwxgmac2_setup(struct stmmac_priv *priv) mac->mcast_bits_log2 = ilog2(mac->multicast_filter_bins); mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE | - MAC_1000FD | MAC_2500FD | MAC_5000FD | - MAC_10000FD; + MAC_10 | MAC_100 | MAC_1000FD | + MAC_2500FD | MAC_5000FD | MAC_10000FD; mac->link.duplex = 0; mac->link.speed10 = XGMAC_CONFIG_SS_10_MII; mac->link.speed100 = XGMAC_CONFIG_SS_100_MII; @@ -1638,6 +1556,7 @@ int dwxgmac2_setup(struct stmmac_priv *priv) mac->mii.reg_mask = GENMASK(15, 0); mac->mii.clk_csr_shift = 19; mac->mii.clk_csr_mask = GENMASK(21, 19); + mac->num_vlan = stmmac_get_num_vlan(priv->ioaddr); return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c index 389aad7b5c1e..a2980482fcce 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_descs.c @@ -4,6 +4,7 @@ * stmmac XGMAC support. */ +#include <linux/bitfield.h> #include <linux/stmmac.h> #include "common.h" #include "dwxgmac2.h" @@ -69,6 +70,21 @@ static int dwxgmac2_get_tx_ls(struct dma_desc *p) return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0; } +static u16 dwxgmac2_wrback_get_rx_vlan_tci(struct dma_desc *p) +{ + return le32_to_cpu(p->des0) & XGMAC_RDES0_VLAN_TAG_MASK; +} + +static bool dwxgmac2_wrback_get_rx_vlan_valid(struct dma_desc *p) +{ + u32 et_lt; + + et_lt = FIELD_GET(XGMAC_RDES3_ET_LT, le32_to_cpu(p->des3)); + + return et_lt >= XGMAC_ET_LT_VLAN_STAG && + et_lt <= XGMAC_ET_LT_DVLAN_STAG_CTAG; +} + static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe) { return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL); @@ -351,6 +367,8 @@ const struct stmmac_desc_ops dwxgmac210_desc_ops = { .set_tx_owner = dwxgmac2_set_tx_owner, .set_rx_owner = dwxgmac2_set_rx_owner, .get_tx_ls = dwxgmac2_get_tx_ls, + .get_rx_vlan_tci = dwxgmac2_wrback_get_rx_vlan_tci, + .get_rx_vlan_valid = dwxgmac2_wrback_get_rx_vlan_valid, .get_rx_frame_len = dwxgmac2_get_rx_frame_len, .enable_tx_timestamp = dwxgmac2_enable_tx_timestamp, .get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status, diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index 7840bc403788..cc1bdc0975d5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -84,7 +84,6 @@ static void dwxgmac2_dma_init_tx_chan(struct stmmac_priv *priv, static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) { u32 value = readl(ioaddr + XGMAC_DMA_SYSBUS_MODE); - int i; if (axi->axi_lpi_en) value |= XGMAC_EN_LPI; @@ -102,32 +101,12 @@ static void dwxgmac2_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi) if (!axi->axi_fb) value |= XGMAC_UNDEF; - value &= ~XGMAC_BLEN; - for (i = 0; i < AXI_BLEN; i++) { - switch (axi->axi_blen[i]) { - case 256: - value |= XGMAC_BLEN256; - break; - case 128: - value |= XGMAC_BLEN128; - break; - case 64: - value |= XGMAC_BLEN64; - break; - case 32: - value |= XGMAC_BLEN32; - break; - case 16: - value |= XGMAC_BLEN16; - break; - case 8: - value |= XGMAC_BLEN8; - break; - case 4: - value |= XGMAC_BLEN4; - break; - } - } + /* Depending on the UNDEF bit the Master AXI will perform any burst + * length according to the BLEN programmed (by default all BLEN are + * set). Note that the UNDEF bit is readonly, and is the inverse of + * Bus Mode bit 16. + */ + value = (value & ~DMA_AXI_BLEN_MASK) | axi->axi_blen_regval; writel(value, ioaddr + XGMAC_DMA_SYSBUS_MODE); writel(XGMAC_TDPS, ioaddr + XGMAC_TX_EDMA_CTRL); @@ -203,10 +182,6 @@ static void dwxgmac2_dma_rx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, } writel(value, ioaddr + XGMAC_MTL_RXQ_OPMODE(channel)); - - /* Enable MTL RX overflow */ - value = readl(ioaddr + XGMAC_MTL_QINTEN(channel)); - writel(value | XGMAC_RXOIE, ioaddr + XGMAC_MTL_QINTEN(channel)); } static void dwxgmac2_dma_tx_mode(struct stmmac_priv *priv, void __iomem *ioaddr, @@ -364,19 +339,17 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, } /* TX/RX NORMAL interrupts */ - if (likely(intr_status & XGMAC_NIS)) { - if (likely(intr_status & XGMAC_RI)) { - u64_stats_update_begin(&stats->syncp); - u64_stats_inc(&stats->rx_normal_irq_n[chan]); - u64_stats_update_end(&stats->syncp); - ret |= handle_rx; - } - if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { - u64_stats_update_begin(&stats->syncp); - u64_stats_inc(&stats->tx_normal_irq_n[chan]); - u64_stats_update_end(&stats->syncp); - ret |= handle_tx; - } + if (likely(intr_status & XGMAC_RI)) { + u64_stats_update_begin(&stats->syncp); + u64_stats_inc(&stats->rx_normal_irq_n[chan]); + u64_stats_update_end(&stats->syncp); + ret |= handle_rx; + } + if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { + u64_stats_update_begin(&stats->syncp); + u64_stats_inc(&stats->tx_normal_irq_n[chan]); + u64_stats_update_end(&stats->syncp); + ret |= handle_tx; } /* Clear interrupts */ @@ -388,8 +361,11 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, struct dma_features *dma_cap) { + struct stmmac_priv *priv; u32 hw_cap; + priv = container_of(dma_cap, struct stmmac_priv, dma_cap); + /* MAC HW feature 0 */ hw_cap = readl(ioaddr + XGMAC_HW_FEATURE0); dma_cap->edma = (hw_cap & XGMAC_HWFEAT_EDMA) >> 31; @@ -412,6 +388,8 @@ static int dwxgmac2_get_hw_feature(void __iomem *ioaddr, dma_cap->vlhash = (hw_cap & XGMAC_HWFEAT_VLHASH) >> 4; dma_cap->half_duplex = (hw_cap & XGMAC_HWFEAT_HDSEL) >> 3; dma_cap->mbps_1000 = (hw_cap & XGMAC_HWFEAT_GMIISEL) >> 1; + if (dma_cap->mbps_1000 && priv->synopsys_id >= DWXGMAC_CORE_2_20) + dma_cap->mbps_10_100 = 1; /* MAC HW feature 1 */ hw_cap = readl(ioaddr + XGMAC_HW_FEATURE1); diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c index 31bdbab9a46c..014f7cd79a3c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.c +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c @@ -9,34 +9,46 @@ #include "stmmac_fpe.h" #include "stmmac_ptp.h" #include "stmmac_est.h" +#include "stmmac_vlan.h" #include "dwmac4_descs.h" #include "dwxgmac2.h" -static u32 stmmac_get_id(struct stmmac_priv *priv, u32 id_reg) +struct stmmac_version { + u8 snpsver; + u8 dev_id; +}; + +static void stmmac_get_version(struct stmmac_priv *priv, + struct stmmac_version *ver) { - u32 reg = readl(priv->ioaddr + id_reg); + enum dwmac_core_type core_type = priv->plat->core_type; + unsigned int version_offset; + u32 version; - if (!reg) { - dev_info(priv->device, "Version ID not available\n"); - return 0x0; - } + ver->snpsver = 0; + ver->dev_id = 0; - dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n", - (unsigned int)(reg & GENMASK(15, 8)) >> 8, - (unsigned int)(reg & GENMASK(7, 0))); - return reg & GENMASK(7, 0); -} + if (core_type == DWMAC_CORE_MAC100) + return; -static u32 stmmac_get_dev_id(struct stmmac_priv *priv, u32 id_reg) -{ - u32 reg = readl(priv->ioaddr + id_reg); + if (core_type == DWMAC_CORE_GMAC) + version_offset = GMAC_VERSION; + else + version_offset = GMAC4_VERSION; - if (!reg) { + version = readl(priv->ioaddr + version_offset); + if (version == 0) { dev_info(priv->device, "Version ID not available\n"); - return 0x0; + return; } - return (reg & GENMASK(15, 8)) >> 8; + dev_info(priv->device, "User ID: 0x%x, Synopsys ID: 0x%x\n", + FIELD_GET(DWMAC_USERVER, version), + FIELD_GET(DWMAC_SNPSVER, version)); + + ver->snpsver = FIELD_GET(DWMAC_SNPSVER, version); + if (core_type == DWMAC_CORE_XGMAC) + ver->dev_id = FIELD_GET(DWMAC_USERVER, version); } static void stmmac_dwmac_mode_quirk(struct stmmac_priv *priv) @@ -91,23 +103,19 @@ static int stmmac_dwxlgmac_quirks(struct stmmac_priv *priv) return 0; } -int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr) +int stmmac_reset(struct stmmac_priv *priv) { - struct plat_stmmacenet_data *plat = priv ? priv->plat : NULL; - - if (!priv) - return -EINVAL; + struct plat_stmmacenet_data *plat = priv->plat; + void __iomem *ioaddr = priv->ioaddr; if (plat && plat->fix_soc_reset) - return plat->fix_soc_reset(plat, ioaddr); + return plat->fix_soc_reset(priv, ioaddr); return stmmac_do_callback(priv, dma, reset, ioaddr); } static const struct stmmac_hwif_entry { - bool gmac; - bool gmac4; - bool xgmac; + enum dwmac_core_type core_type; u32 min_id; u32 dev_id; const struct stmmac_regs_off regs; @@ -120,14 +128,13 @@ static const struct stmmac_hwif_entry { const void *tc; const void *mmc; const void *est; + const void *vlan; int (*setup)(struct stmmac_priv *priv); int (*quirks)(struct stmmac_priv *priv); } stmmac_hw[] = { /* NOTE: New HW versions shall go to the end of this table */ { - .gmac = false, - .gmac4 = false, - .xgmac = false, + .core_type = DWMAC_CORE_MAC100, .min_id = 0, .regs = { .ptp_off = PTP_GMAC3_X_OFFSET, @@ -144,9 +151,7 @@ static const struct stmmac_hwif_entry { .setup = dwmac100_setup, .quirks = stmmac_dwmac1_quirks, }, { - .gmac = true, - .gmac4 = false, - .xgmac = false, + .core_type = DWMAC_CORE_GMAC, .min_id = 0, .regs = { .ptp_off = PTP_GMAC3_X_OFFSET, @@ -163,9 +168,7 @@ static const struct stmmac_hwif_entry { .setup = dwmac1000_setup, .quirks = stmmac_dwmac1_quirks, }, { - .gmac = false, - .gmac4 = true, - .xgmac = false, + .core_type = DWMAC_CORE_GMAC4, .min_id = 0, .regs = { .ptp_off = PTP_GMAC4_OFFSET, @@ -175,6 +178,7 @@ static const struct stmmac_hwif_entry { .desc = &dwmac4_desc_ops, .dma = &dwmac4_dma_ops, .mac = &dwmac4_ops, + .vlan = &dwmac_vlan_ops, .hwtimestamp = &stmmac_ptp, .ptp = &stmmac_ptp_clock_ops, .mode = NULL, @@ -184,9 +188,7 @@ static const struct stmmac_hwif_entry { .setup = dwmac4_setup, .quirks = stmmac_dwmac4_quirks, }, { - .gmac = false, - .gmac4 = true, - .xgmac = false, + .core_type = DWMAC_CORE_GMAC4, .min_id = DWMAC_CORE_4_00, .regs = { .ptp_off = PTP_GMAC4_OFFSET, @@ -197,6 +199,7 @@ static const struct stmmac_hwif_entry { .desc = &dwmac4_desc_ops, .dma = &dwmac4_dma_ops, .mac = &dwmac410_ops, + .vlan = &dwmac_vlan_ops, .hwtimestamp = &stmmac_ptp, .ptp = &stmmac_ptp_clock_ops, .mode = &dwmac4_ring_mode_ops, @@ -206,9 +209,7 @@ static const struct stmmac_hwif_entry { .setup = dwmac4_setup, .quirks = NULL, }, { - .gmac = false, - .gmac4 = true, - .xgmac = false, + .core_type = DWMAC_CORE_GMAC4, .min_id = DWMAC_CORE_4_10, .regs = { .ptp_off = PTP_GMAC4_OFFSET, @@ -219,6 +220,7 @@ static const struct stmmac_hwif_entry { .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, .mac = &dwmac410_ops, + .vlan = &dwmac_vlan_ops, .hwtimestamp = &stmmac_ptp, .ptp = &stmmac_ptp_clock_ops, .mode = &dwmac4_ring_mode_ops, @@ -228,9 +230,7 @@ static const struct stmmac_hwif_entry { .setup = dwmac4_setup, .quirks = NULL, }, { - .gmac = false, - .gmac4 = true, - .xgmac = false, + .core_type = DWMAC_CORE_GMAC4, .min_id = DWMAC_CORE_5_10, .regs = { .ptp_off = PTP_GMAC4_OFFSET, @@ -241,6 +241,7 @@ static const struct stmmac_hwif_entry { .desc = &dwmac4_desc_ops, .dma = &dwmac410_dma_ops, .mac = &dwmac510_ops, + .vlan = &dwmac_vlan_ops, .hwtimestamp = &stmmac_ptp, .ptp = &stmmac_ptp_clock_ops, .mode = &dwmac4_ring_mode_ops, @@ -250,9 +251,7 @@ static const struct stmmac_hwif_entry { .setup = dwmac4_setup, .quirks = NULL, }, { - .gmac = false, - .gmac4 = false, - .xgmac = true, + .core_type = DWMAC_CORE_XGMAC, .min_id = DWXGMAC_CORE_2_10, .dev_id = DWXGMAC_ID, .regs = { @@ -264,6 +263,7 @@ static const struct stmmac_hwif_entry { .desc = &dwxgmac210_desc_ops, .dma = &dwxgmac210_dma_ops, .mac = &dwxgmac210_ops, + .vlan = &dwxgmac210_vlan_ops, .hwtimestamp = &stmmac_ptp, .ptp = &stmmac_ptp_clock_ops, .mode = NULL, @@ -273,9 +273,7 @@ static const struct stmmac_hwif_entry { .setup = dwxgmac2_setup, .quirks = NULL, }, { - .gmac = false, - .gmac4 = false, - .xgmac = true, + .core_type = DWMAC_CORE_XGMAC, .min_id = DWXLGMAC_CORE_2_00, .dev_id = DWXLGMAC_ID, .regs = { @@ -287,6 +285,7 @@ static const struct stmmac_hwif_entry { .desc = &dwxgmac210_desc_ops, .dma = &dwxgmac210_dma_ops, .mac = &dwxlgmac2_ops, + .vlan = &dwxlgmac2_vlan_ops, .hwtimestamp = &stmmac_ptp, .ptp = &stmmac_ptp_clock_ops, .mode = NULL, @@ -298,99 +297,114 @@ static const struct stmmac_hwif_entry { }, }; +static const struct stmmac_hwif_entry * +stmmac_hwif_find(enum dwmac_core_type core_type, u8 snpsver, u8 dev_id) +{ + const struct stmmac_hwif_entry *entry; + int i; + + for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) { + entry = &stmmac_hw[i]; + + if (core_type != entry->core_type) + continue; + /* Use synopsys_id var because some setups can override this */ + if (snpsver < entry->min_id) + continue; + if (core_type == DWMAC_CORE_XGMAC && + dev_id != entry->dev_id) + continue; + + return entry; + } + + return NULL; +} + int stmmac_hwif_init(struct stmmac_priv *priv) { - bool needs_xgmac = priv->plat->has_xgmac; - bool needs_gmac4 = priv->plat->has_gmac4; - bool needs_gmac = priv->plat->has_gmac; + enum dwmac_core_type core_type = priv->plat->core_type; const struct stmmac_hwif_entry *entry; + struct stmmac_version version; struct mac_device_info *mac; bool needs_setup = true; - u32 id, dev_id = 0; - int i, ret; - - if (needs_gmac) { - id = stmmac_get_id(priv, GMAC_VERSION); - } else if (needs_gmac4 || needs_xgmac) { - id = stmmac_get_id(priv, GMAC4_VERSION); - if (needs_xgmac) - dev_id = stmmac_get_dev_id(priv, GMAC4_VERSION); - } else { - id = 0; - } + int ret; + + stmmac_get_version(priv, &version); /* Save ID for later use */ - priv->synopsys_id = id; + priv->synopsys_id = version.snpsver; /* Lets assume some safe values first */ - priv->ptpaddr = priv->ioaddr + - (needs_gmac4 ? PTP_GMAC4_OFFSET : PTP_GMAC3_X_OFFSET); - priv->mmcaddr = priv->ioaddr + - (needs_gmac4 ? MMC_GMAC4_OFFSET : MMC_GMAC3_X_OFFSET); - if (needs_gmac4) + if (core_type == DWMAC_CORE_GMAC4) { + priv->ptpaddr = priv->ioaddr + PTP_GMAC4_OFFSET; + priv->mmcaddr = priv->ioaddr + MMC_GMAC4_OFFSET; priv->estaddr = priv->ioaddr + EST_GMAC4_OFFSET; - else if (needs_xgmac) - priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET; - - /* Check for HW specific setup first */ - if (priv->plat->setup) { - mac = priv->plat->setup(priv); - needs_setup = false; } else { - mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); + priv->ptpaddr = priv->ioaddr + PTP_GMAC3_X_OFFSET; + priv->mmcaddr = priv->ioaddr + MMC_GMAC3_X_OFFSET; + if (core_type == DWMAC_CORE_XGMAC) + priv->estaddr = priv->ioaddr + EST_XGMAC_OFFSET; } + mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL); if (!mac) return -ENOMEM; + /* Check for HW specific setup first */ + if (priv->plat->mac_setup) { + ret = priv->plat->mac_setup(priv, mac); + if (ret) + return ret; + + needs_setup = false; + } + + spin_lock_init(&mac->irq_ctrl_lock); + /* Fallback to generic HW */ - for (i = ARRAY_SIZE(stmmac_hw) - 1; i >= 0; i--) { - entry = &stmmac_hw[i]; - if (needs_gmac ^ entry->gmac) - continue; - if (needs_gmac4 ^ entry->gmac4) - continue; - if (needs_xgmac ^ entry->xgmac) - continue; - /* Use synopsys_id var because some setups can override this */ - if (priv->synopsys_id < entry->min_id) - continue; - if (needs_xgmac && (dev_id ^ entry->dev_id)) - continue; + /* Use synopsys_id var because some setups can override this */ + entry = stmmac_hwif_find(core_type, priv->synopsys_id, version.dev_id); + if (!entry) { + dev_err(priv->device, + "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n", + version.snpsver, core_type == DWMAC_CORE_GMAC, + core_type == DWMAC_CORE_GMAC4); - /* Only use generic HW helpers if needed */ - mac->desc = mac->desc ? : entry->desc; - mac->dma = mac->dma ? : entry->dma; - mac->mac = mac->mac ? : entry->mac; - mac->ptp = mac->ptp ? : entry->hwtimestamp; - mac->mode = mac->mode ? : entry->mode; - mac->tc = mac->tc ? : entry->tc; - mac->mmc = mac->mmc ? : entry->mmc; - mac->est = mac->est ? : entry->est; - - priv->hw = mac; - priv->fpe_cfg.reg = entry->regs.fpe_reg; - priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; - priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off; - memcpy(&priv->ptp_clock_ops, entry->ptp, - sizeof(struct ptp_clock_info)); - if (entry->est) - priv->estaddr = priv->ioaddr + entry->regs.est_off; - - /* Entry found */ - if (needs_setup) { - ret = entry->setup(priv); - if (ret) - return ret; - } + return -EINVAL; + } - /* Save quirks, if needed for posterior use */ - priv->hwif_quirks = entry->quirks; - return 0; + /* Only use generic HW helpers if needed */ + mac->desc = mac->desc ? : entry->desc; + mac->dma = mac->dma ? : entry->dma; + mac->mac = mac->mac ? : entry->mac; + mac->ptp = mac->ptp ? : entry->hwtimestamp; + mac->mode = mac->mode ? : entry->mode; + mac->tc = mac->tc ? : entry->tc; + mac->mmc = mac->mmc ? : entry->mmc; + mac->est = mac->est ? : entry->est; + mac->vlan = mac->vlan ? : entry->vlan; + + priv->hw = mac; + priv->fpe_cfg.reg = entry->regs.fpe_reg; + priv->ptpaddr = priv->ioaddr + entry->regs.ptp_off; + priv->mmcaddr = priv->ioaddr + entry->regs.mmc_off; + memcpy(&priv->ptp_clock_ops, entry->ptp, + sizeof(struct ptp_clock_info)); + + if (entry->est) + priv->estaddr = priv->ioaddr + entry->regs.est_off; + + /* Entry found */ + if (needs_setup) { + ret = entry->setup(priv); + if (ret) + return ret; } - dev_err(priv->device, "Failed to find HW IF (id=0x%x, gmac=%d/%d)\n", - id, needs_gmac, needs_gmac4); - return -EINVAL; + /* Save quirks, if needed for posterior use */ + priv->hwif_quirks = entry->quirks; + + return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index 27c63a9fc163..df6e8a567b1f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -201,6 +201,7 @@ struct stmmac_dma_ops { void (*dma_diagnostic_fr)(struct stmmac_extra_stats *x, void __iomem *ioaddr); void (*enable_dma_transmission)(void __iomem *ioaddr, u32 chan); + void (*enable_dma_reception)(void __iomem *ioaddr, u32 chan); void (*enable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr, u32 chan, bool rx, bool tx); void (*disable_dma_irq)(struct stmmac_priv *priv, void __iomem *ioaddr, @@ -261,6 +262,8 @@ struct stmmac_dma_ops { stmmac_do_void_callback(__priv, dma, dma_diagnostic_fr, __args) #define stmmac_enable_dma_transmission(__priv, __args...) \ stmmac_do_void_callback(__priv, dma, enable_dma_transmission, __args) +#define stmmac_enable_dma_reception(__priv, __args...) \ + stmmac_do_void_callback(__priv, dma, enable_dma_reception, __args) #define stmmac_enable_dma_irq(__priv, __args...) \ stmmac_do_void_callback(__priv, dma, enable_dma_irq, __priv, __args) #define stmmac_disable_dma_irq(__priv, __args...) \ @@ -300,7 +303,6 @@ struct stmmac_dma_ops { struct mac_device_info; struct net_device; -struct rgmii_adv; struct stmmac_tc_entry; struct stmmac_pps_cfg; struct stmmac_rss; @@ -314,10 +316,14 @@ enum stmmac_lpi_mode { /* Helpers to program the MAC core */ struct stmmac_ops { + /* Initialise any PCS instances */ + int (*pcs_init)(struct stmmac_priv *priv); /* MAC core initialization */ void (*core_init)(struct mac_device_info *hw, struct net_device *dev); /* Update MAC capabilities */ void (*update_caps)(struct stmmac_priv *priv); + /* Change the interrupt enable setting. Enable takes precedence. */ + void (*irq_modify)(struct mac_device_info *hw, u32 disable, u32 enable); /* Enable the MAC RX/TX */ void (*set_mac)(void __iomem *ioaddr, bool enable); /* Enable and verify that the IPC module is supported */ @@ -375,9 +381,8 @@ struct stmmac_ops { struct stmmac_extra_stats *x, u32 rx_queues, u32 tx_queues); /* PCS calls */ - void (*pcs_ctrl_ane)(void __iomem *ioaddr, bool ane, bool srgmi_ral, - bool loopback); - void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv); + void (*pcs_ctrl_ane)(struct stmmac_priv *priv, bool ane, + bool srgmi_ral); /* Safety Features */ int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp, struct stmmac_safety_feature_cfg *safety_cfg); @@ -398,21 +403,6 @@ struct stmmac_ops { /* RSS */ int (*rss_configure)(struct mac_device_info *hw, struct stmmac_rss *cfg, u32 num_rxq); - /* VLAN */ - void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, - u16 perfect_match, bool is_double); - void (*enable_vlan)(struct mac_device_info *hw, u32 type); - void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc, - struct sk_buff *skb); - void (*set_hw_vlan_mode)(struct mac_device_info *hw); - int (*add_hw_vlan_rx_fltr)(struct net_device *dev, - struct mac_device_info *hw, - __be16 proto, u16 vid); - int (*del_hw_vlan_rx_fltr)(struct net_device *dev, - struct mac_device_info *hw, - __be16 proto, u16 vid); - void (*restore_hw_vlan_rx_fltr)(struct net_device *dev, - struct mac_device_info *hw); /* TX Timestamp */ int (*get_mac_tx_timestamp)(struct mac_device_info *hw, u64 *ts); /* Source Address Insertion / Replacement */ @@ -430,10 +420,14 @@ struct stmmac_ops { u32 pclass); }; +#define stmmac_mac_pcs_init(__priv) \ + stmmac_do_callback(__priv, mac, pcs_init, __priv) #define stmmac_core_init(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, core_init, __args) #define stmmac_mac_update_caps(__priv) \ stmmac_do_void_callback(__priv, mac, update_caps, __priv) +#define stmmac_mac_irq_modify(__priv, __args...) \ + stmmac_do_void_callback(__priv, mac, irq_modify, (__priv)->hw, __args) #define stmmac_mac_set(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, set_mac, __args) #define stmmac_rx_ipc(__priv, __args...) \ @@ -481,9 +475,7 @@ struct stmmac_ops { #define stmmac_mac_debug(__priv, __args...) \ stmmac_do_void_callback(__priv, mac, debug, __priv, __args) #define stmmac_pcs_ctrl_ane(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, pcs_ctrl_ane, __args) -#define stmmac_pcs_get_adv_lp(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, pcs_get_adv_lp, __args) + stmmac_do_void_callback(__priv, mac, pcs_ctrl_ane, __priv, __args) #define stmmac_safety_feat_config(__priv, __args...) \ stmmac_do_callback(__priv, mac, safety_feat_config, __args) #define stmmac_safety_feat_irq_status(__priv, __args...) \ @@ -498,20 +490,6 @@ struct stmmac_ops { stmmac_do_void_callback(__priv, mac, set_mac_loopback, __args) #define stmmac_rss_configure(__priv, __args...) \ stmmac_do_callback(__priv, mac, rss_configure, __args) -#define stmmac_update_vlan_hash(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, update_vlan_hash, __args) -#define stmmac_enable_vlan(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, enable_vlan, __args) -#define stmmac_rx_hw_vlan(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, rx_hw_vlan, __args) -#define stmmac_set_hw_vlan_mode(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, set_hw_vlan_mode, __args) -#define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \ - stmmac_do_callback(__priv, mac, add_hw_vlan_rx_fltr, __args) -#define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \ - stmmac_do_callback(__priv, mac, del_hw_vlan_rx_fltr, __args) -#define stmmac_restore_hw_vlan_rx_fltr(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, restore_hw_vlan_rx_fltr, __args) #define stmmac_get_mac_tx_timestamp(__priv, __args...) \ stmmac_do_callback(__priv, mac, get_mac_tx_timestamp, __args) #define stmmac_sarc_configure(__priv, __args...) \ @@ -566,7 +544,7 @@ struct stmmac_rx_queue; struct stmmac_mode_ops { void (*init) (void *des, dma_addr_t phy_addr, unsigned int size, unsigned int extend_desc); - unsigned int (*is_jumbo_frm) (int len, int ehn_desc); + bool (*is_jumbo_frm)(unsigned int len, bool enh_desc); int (*jumbo_frm)(struct stmmac_tx_queue *tx_q, struct sk_buff *skb, int csum); int (*set_16kib_bfsize)(int mtu); @@ -659,6 +637,39 @@ struct stmmac_est_ops { #define stmmac_est_irq_status(__priv, __args...) \ stmmac_do_void_callback(__priv, est, irq_status, __args) +struct stmmac_vlan_ops { + /* VLAN */ + void (*update_vlan_hash)(struct mac_device_info *hw, u32 hash, + u16 perfect_match, bool is_double); + void (*enable_vlan)(struct mac_device_info *hw, u32 type); + void (*rx_hw_vlan)(struct mac_device_info *hw, struct dma_desc *rx_desc, + struct sk_buff *skb); + void (*set_hw_vlan_mode)(struct mac_device_info *hw); + int (*add_hw_vlan_rx_fltr)(struct net_device *dev, + struct mac_device_info *hw, + __be16 proto, u16 vid); + int (*del_hw_vlan_rx_fltr)(struct net_device *dev, + struct mac_device_info *hw, + __be16 proto, u16 vid); + void (*restore_hw_vlan_rx_fltr)(struct net_device *dev, + struct mac_device_info *hw); +}; + +#define stmmac_update_vlan_hash(__priv, __args...) \ + stmmac_do_void_callback(__priv, vlan, update_vlan_hash, __args) +#define stmmac_enable_vlan(__priv, __args...) \ + stmmac_do_void_callback(__priv, vlan, enable_vlan, __args) +#define stmmac_rx_hw_vlan(__priv, __args...) \ + stmmac_do_void_callback(__priv, vlan, rx_hw_vlan, __args) +#define stmmac_set_hw_vlan_mode(__priv, __args...) \ + stmmac_do_void_callback(__priv, vlan, set_hw_vlan_mode, __args) +#define stmmac_add_hw_vlan_rx_fltr(__priv, __args...) \ + stmmac_do_callback(__priv, vlan, add_hw_vlan_rx_fltr, __args) +#define stmmac_del_hw_vlan_rx_fltr(__priv, __args...) \ + stmmac_do_callback(__priv, vlan, del_hw_vlan_rx_fltr, __args) +#define stmmac_restore_hw_vlan_rx_fltr(__priv, __args...) \ + stmmac_do_void_callback(__priv, vlan, restore_hw_vlan_rx_fltr, __args) + struct stmmac_regs_off { const struct stmmac_fpe_reg *fpe_reg; u32 ptp_off; @@ -690,7 +701,7 @@ extern const struct stmmac_tc_ops dwmac510_tc_ops; #define GMAC_VERSION 0x00000020 /* GMAC CORE Version */ #define GMAC4_VERSION 0x00000110 /* GMAC4+ CORE Version */ -int stmmac_reset(struct stmmac_priv *priv, void __iomem *ioaddr); +int stmmac_reset(struct stmmac_priv *priv); int stmmac_hwif_init(struct stmmac_priv *priv); #endif /* __STMMAC_HWIF_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c index d218412ca832..382d94a3b972 100644 --- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c @@ -91,14 +91,9 @@ static int jumbo_frm(struct stmmac_tx_queue *tx_q, struct sk_buff *skb, return entry; } -static unsigned int is_jumbo_frm(int len, int enh_desc) +static bool is_jumbo_frm(unsigned int len, bool enh_desc) { - unsigned int ret = 0; - - if (len >= BUF_SIZE_4KiB) - ret = 1; - - return ret; + return len >= BUF_SIZE_4KiB; } static void refill_desc3(struct stmmac_rx_queue *rx_q, struct dma_desc *p) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index bddfa0f4aa21..012b0a477255 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -25,6 +25,8 @@ #include <net/xdp.h> #include <uapi/linux/bpf.h> +struct stmmac_pcs; + struct stmmac_resources { void __iomem *addr; u8 mac[ETH_ALEN]; @@ -149,21 +151,9 @@ struct stmmac_channel { }; struct stmmac_fpe_cfg { - /* Serialize access to MAC Merge state between ethtool requests - * and link state updates. - */ - spinlock_t lock; - + struct ethtool_mmsv mmsv; const struct stmmac_fpe_reg *reg; - u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */ - - enum ethtool_mm_verify_status status; - struct timer_list verify_timer; - bool verify_enabled; - int verify_retries; - bool pmac_enabled; - u32 verify_time; - bool tx_enabled; + u32 fpe_csr; /* MAC_FPE_CTRL_STS reg cache */ }; struct stmmac_tc_entry { @@ -264,11 +254,12 @@ struct stmmac_priv { int hwts_tx_en; bool tx_path_in_lpi_mode; bool tso; - int sph; - int sph_cap; + bool sph_active; + bool sph_capable; u32 sarc_type; u32 rx_riwt[MTL_MAX_RX_QUEUES]; int hwts_rx_en; + bool tsfupdt_coarse; void __iomem *ioaddr; struct net_device *dev; @@ -285,6 +276,8 @@ struct stmmac_priv { unsigned int pause_time; struct mii_bus *mii; + struct stmmac_pcs *integrated_pcs; + struct phylink_config phylink_config; struct phylink *phylink; @@ -299,10 +292,10 @@ struct stmmac_priv { int hw_cap_support; int synopsys_id; u32 msg_enable; + /* Our MAC Wake-on-Lan options */ int wolopts; int wol_irq; - bool wol_irq_disabled; - int clk_csr; + u32 gmii_address_bus_config; struct timer_list eee_ctrl_timer; int lpi_irq; u32 tx_lpi_timer; @@ -313,7 +306,7 @@ struct stmmac_priv { unsigned int mode; unsigned int chain_mode; int extend_desc; - struct hwtstamp_config tstamp_config; + struct kernel_hwtstamp_config tstamp_config; struct ptp_clock *ptp_clock; struct ptp_clock_info ptp_clock_ops; unsigned int default_addend; @@ -377,6 +370,8 @@ struct stmmac_priv { /* XDP BPF Program */ unsigned long *af_xdp_zc_qps; struct bpf_prog *xdp_prog; + + struct devlink *devlink; }; enum stmmac_state { @@ -386,18 +381,22 @@ enum stmmac_state { STMMAC_SERVICE_SCHED, }; +extern const struct dev_pm_ops stmmac_simple_pm_ops; + int stmmac_mdio_unregister(struct net_device *ndev); int stmmac_mdio_register(struct net_device *ndev); int stmmac_mdio_reset(struct mii_bus *mii); +void stmmac_mdio_lock(struct stmmac_priv *priv); +void stmmac_mdio_unlock(struct stmmac_priv *priv); 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); void stmmac_ptp_register(struct stmmac_priv *priv); void stmmac_ptp_unregister(struct stmmac_priv *priv); int stmmac_xdp_open(struct net_device *dev); void stmmac_xdp_release(struct net_device *dev); +int stmmac_get_phy_intf_sel(phy_interface_t interface); int stmmac_resume(struct device *dev); int stmmac_suspend(struct device *dev); void stmmac_dvr_remove(struct device *dev); @@ -406,10 +405,11 @@ int stmmac_dvr_probe(struct device *device, struct stmmac_resources *res); int stmmac_reinit_queues(struct net_device *dev, u32 rx_cnt, u32 tx_cnt); int stmmac_reinit_ringparam(struct net_device *dev, u32 rx_size, u32 tx_size); -int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled); int stmmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, phy_interface_t interface, int speed); +struct plat_stmmacenet_data *stmmac_plat_dat_alloc(struct device *dev); + static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv) { return !!priv->xdp_prog; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c index c9693f77e1f6..afc516059b89 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.c @@ -32,6 +32,11 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg, int i, ret = 0; u32 ctrl; + if (!ptp_rate) { + netdev_warn(priv->dev, "Invalid PTP rate"); + return -EINVAL; + } + ret |= est_write(est_addr, EST_BTR_LOW, cfg->btr[0], false); ret |= est_write(est_addr, EST_BTR_HIGH, cfg->btr[1], false); ret |= est_write(est_addr, EST_TER, cfg->ter, false); @@ -48,7 +53,7 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg, } ctrl = readl(est_addr + EST_CONTROL); - if (priv->plat->has_xgmac) { + if (priv->plat->core_type == DWMAC_CORE_XGMAC) { ctrl &= ~EST_XGMAC_PTOV; ctrl |= ((NSEC_PER_SEC / ptp_rate) * EST_XGMAC_PTOV_MUL) << EST_XGMAC_PTOV_SHIFT; @@ -58,7 +63,7 @@ static int est_configure(struct stmmac_priv *priv, struct stmmac_est *cfg, EST_GMAC5_PTOV_SHIFT; } if (cfg->enable) - ctrl |= EST_EEST | EST_SSWL; + ctrl |= EST_EEST | EST_SSWL | EST_DFBS; else ctrl &= ~EST_EEST; @@ -104,6 +109,10 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, x->mtl_est_hlbs++; + for (i = 0; i < txqcnt; i++) + if (value & BIT(i)) + x->mtl_est_txq_hlbs[i]++; + /* Clear Interrupt */ writel(value, est_addr + EST_SCH_ERR); @@ -126,10 +135,9 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, x->mtl_est_hlbf++; - for (i = 0; i < txqcnt; i++) { + for (i = 0; i < txqcnt; i++) if (feqn & BIT(i)) x->mtl_est_txq_hlbf[i]++; - } /* Clear Interrupt */ writel(feqn, est_addr + EST_FRM_SZ_ERR); @@ -140,7 +148,7 @@ static void est_irq_status(struct stmmac_priv *priv, struct net_device *dev, } if (status & EST_BTRE) { - if (priv->plat->has_xgmac) { + if (priv->plat->core_type == DWMAC_CORE_XGMAC) { btrl = FIELD_GET(EST_XGMAC_BTRL, status); btrl_max = FIELD_MAX(EST_XGMAC_BTRL); } else { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h index d247fa383a6e..f70221c9c84a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_est.h @@ -16,6 +16,7 @@ #define EST_XGMAC_PTOV_MUL 9 #define EST_SSWL BIT(1) #define EST_EEST BIT(0) +#define EST_DFBS BIT(5) #define EST_STATUS 0x00000008 #define EST_GMAC5_BTRL GENMASK(11, 8) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 918a32f8fda8..b155e71aac51 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -37,7 +37,7 @@ #define ETHTOOL_DMA_OFFSET 55 struct stmmac_stats { - char stat_string[ETH_GSTRING_LEN]; + char stat_string[ETH_GSTRING_LEN] __nonstring; int sizeof_stat; int stat_offset; }; @@ -303,9 +303,10 @@ static void stmmac_ethtool_getdrvinfo(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (priv->plat->has_gmac || priv->plat->has_gmac4) + if (priv->plat->core_type == DWMAC_CORE_GMAC || + priv->plat->core_type == DWMAC_CORE_GMAC4) strscpy(info->driver, GMAC_ETHTOOL_NAME, sizeof(info->driver)); - else if (priv->plat->has_xgmac) + else if (priv->plat->core_type == DWMAC_CORE_XGMAC) strscpy(info->driver, XGMAC_ETHTOOL_NAME, sizeof(info->driver)); else strscpy(info->driver, MAC100_ETHTOOL_NAME, @@ -322,84 +323,6 @@ static int stmmac_ethtool_get_link_ksettings(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) && - (priv->hw->pcs & STMMAC_PCS_RGMII || - priv->hw->pcs & STMMAC_PCS_SGMII)) { - struct rgmii_adv adv; - u32 supported, advertising, lp_advertising; - - if (!priv->xstats.pcs_link) { - cmd->base.speed = SPEED_UNKNOWN; - cmd->base.duplex = DUPLEX_UNKNOWN; - return 0; - } - cmd->base.duplex = priv->xstats.pcs_duplex; - - cmd->base.speed = priv->xstats.pcs_speed; - - /* Get and convert ADV/LP_ADV from the HW AN registers */ - if (stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv)) - return -EOPNOTSUPP; /* should never happen indeed */ - - /* Encoding of PSE bits is defined in 802.3z, 37.2.1.4 */ - - ethtool_convert_link_mode_to_legacy_u32( - &supported, cmd->link_modes.supported); - ethtool_convert_link_mode_to_legacy_u32( - &advertising, cmd->link_modes.advertising); - ethtool_convert_link_mode_to_legacy_u32( - &lp_advertising, cmd->link_modes.lp_advertising); - - if (adv.pause & STMMAC_PCS_PAUSE) - advertising |= ADVERTISED_Pause; - if (adv.pause & STMMAC_PCS_ASYM_PAUSE) - advertising |= ADVERTISED_Asym_Pause; - if (adv.lp_pause & STMMAC_PCS_PAUSE) - lp_advertising |= ADVERTISED_Pause; - if (adv.lp_pause & STMMAC_PCS_ASYM_PAUSE) - lp_advertising |= ADVERTISED_Asym_Pause; - - /* Reg49[3] always set because ANE is always supported */ - cmd->base.autoneg = ADVERTISED_Autoneg; - supported |= SUPPORTED_Autoneg; - advertising |= ADVERTISED_Autoneg; - lp_advertising |= ADVERTISED_Autoneg; - - if (adv.duplex) { - supported |= (SUPPORTED_1000baseT_Full | - SUPPORTED_100baseT_Full | - SUPPORTED_10baseT_Full); - advertising |= (ADVERTISED_1000baseT_Full | - ADVERTISED_100baseT_Full | - ADVERTISED_10baseT_Full); - } else { - supported |= (SUPPORTED_1000baseT_Half | - SUPPORTED_100baseT_Half | - SUPPORTED_10baseT_Half); - advertising |= (ADVERTISED_1000baseT_Half | - ADVERTISED_100baseT_Half | - ADVERTISED_10baseT_Half); - } - if (adv.lp_duplex) - lp_advertising |= (ADVERTISED_1000baseT_Full | - ADVERTISED_100baseT_Full | - ADVERTISED_10baseT_Full); - else - lp_advertising |= (ADVERTISED_1000baseT_Half | - ADVERTISED_100baseT_Half | - ADVERTISED_10baseT_Half); - cmd->base.port = PORT_OTHER; - - ethtool_convert_legacy_u32_to_link_mode( - cmd->link_modes.supported, supported); - ethtool_convert_legacy_u32_to_link_mode( - cmd->link_modes.advertising, advertising); - ethtool_convert_legacy_u32_to_link_mode( - cmd->link_modes.lp_advertising, lp_advertising); - - return 0; - } - return phylink_ethtool_ksettings_get(priv->phylink, cmd); } @@ -409,20 +332,6 @@ stmmac_ethtool_set_link_ksettings(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS) && - (priv->hw->pcs & STMMAC_PCS_RGMII || - priv->hw->pcs & STMMAC_PCS_SGMII)) { - /* Only support ANE */ - if (cmd->base.autoneg != AUTONEG_ENABLE) - return -EINVAL; - - mutex_lock(&priv->lock); - stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0); - mutex_unlock(&priv->lock); - - return 0; - } - return phylink_ethtool_ksettings_set(priv->phylink, cmd); } @@ -443,9 +352,9 @@ static int stmmac_ethtool_get_regs_len(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); - if (priv->plat->has_xgmac) + if (priv->plat->core_type == DWMAC_CORE_XGMAC) return XGMAC_REGSIZE * 4; - else if (priv->plat->has_gmac4) + else if (priv->plat->core_type == DWMAC_CORE_GMAC4) return GMAC4_REG_SPACE_SIZE; return REG_SPACE_SIZE; } @@ -460,12 +369,12 @@ static void stmmac_ethtool_gregs(struct net_device *dev, stmmac_dump_dma_regs(priv, priv->ioaddr, reg_space); /* Copy DMA registers to where ethtool expects them */ - if (priv->plat->has_gmac4) { + if (priv->plat->core_type == DWMAC_CORE_GMAC4) { /* GMAC4 dumps its DMA registers at its DMA_CHAN_BASE_ADDR */ memcpy(®_space[ETHTOOL_DMA_OFFSET], ®_space[GMAC4_DMA_CHAN_BASE_ADDR / 4], NUM_DWMAC4_DMA_REGS * 4); - } else if (!priv->plat->has_xgmac) { + } else if (priv->plat->core_type != DWMAC_CORE_XGMAC) { memcpy(®_space[ETHTOOL_DMA_OFFSET], ®_space[DMA_BUS_MODE / 4], NUM_DWMAC1000_DMA_REGS * 4); @@ -515,15 +424,8 @@ stmmac_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct stmmac_priv *priv = netdev_priv(netdev); - struct rgmii_adv adv_lp; - if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { - pause->autoneg = 1; - if (!adv_lp.pause) - return; - } else { - phylink_ethtool_get_pauseparam(priv->phylink, pause); - } + phylink_ethtool_get_pauseparam(priv->phylink, pause); } static int @@ -531,16 +433,8 @@ stmmac_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { struct stmmac_priv *priv = netdev_priv(netdev); - struct rgmii_adv adv_lp; - if (priv->hw->pcs && !stmmac_pcs_get_adv_lp(priv, priv->ioaddr, &adv_lp)) { - pause->autoneg = 1; - if (!adv_lp.pause) - return -EOPNOTSUPP; - return 0; - } else { - return phylink_ethtool_set_pauseparam(priv->phylink, pause); - } + return phylink_ethtool_set_pauseparam(priv->phylink, pause); } static u64 stmmac_get_rx_normal_irq_n(struct stmmac_priv *priv, int q) @@ -830,64 +724,14 @@ static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->plat->pmt) - return phylink_ethtool_get_wol(priv->phylink, wol); - - mutex_lock(&priv->lock); - if (device_can_wakeup(priv->device)) { - wol->supported = WAKE_MAGIC | WAKE_UCAST; - if (priv->hw_cap_support && !priv->dma_cap.pmt_magic_frame) - wol->supported &= ~WAKE_MAGIC; - wol->wolopts = priv->wolopts; - } - mutex_unlock(&priv->lock); + return phylink_ethtool_get_wol(priv->phylink, wol); } static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct stmmac_priv *priv = netdev_priv(dev); - u32 support = WAKE_MAGIC | WAKE_UCAST; - - if (!device_can_wakeup(priv->device)) - return -EOPNOTSUPP; - if (!priv->plat->pmt) { - int ret = phylink_ethtool_set_wol(priv->phylink, wol); - - if (!ret) - device_set_wakeup_enable(priv->device, !!wol->wolopts); - return ret; - } - - /* By default almost all GMAC devices support the WoL via - * magic frame but we can disable it if the HW capability - * register shows no support for pmt_magic_frame. */ - if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) - wol->wolopts &= ~WAKE_MAGIC; - - if (wol->wolopts & ~support) - return -EINVAL; - - if (wol->wolopts) { - pr_info("stmmac: wakeup enable\n"); - device_set_wakeup_enable(priv->device, 1); - /* Avoid unbalanced enable_irq_wake calls */ - if (priv->wol_irq_disabled) - enable_irq_wake(priv->wol_irq); - priv->wol_irq_disabled = false; - } else { - device_set_wakeup_enable(priv->device, 0); - /* Avoid unbalanced disable_irq_wake calls */ - if (!priv->wol_irq_disabled) - disable_irq_wake(priv->wol_irq); - priv->wol_irq_disabled = true; - } - - mutex_lock(&priv->lock); - priv->wolopts = wol->wolopts; - mutex_unlock(&priv->lock); - - return 0; + return phylink_ethtool_set_wol(priv->phylink, wol); } static int stmmac_ethtool_op_get_eee(struct net_device *dev, @@ -895,9 +739,6 @@ static int stmmac_ethtool_op_get_eee(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->dma_cap.eee) - return -EOPNOTSUPP; - return phylink_ethtool_get_eee(priv->phylink, edata); } @@ -906,9 +747,6 @@ static int stmmac_ethtool_op_set_eee(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if (!priv->dma_cap.eee) - return -EOPNOTSUPP; - return phylink_ethtool_set_eee(priv->phylink, edata); } @@ -1210,36 +1048,16 @@ static int stmmac_get_mm(struct net_device *ndev, struct ethtool_mm_state *state) { struct stmmac_priv *priv = netdev_priv(ndev); - unsigned long flags; u32 frag_size; if (!stmmac_fpe_supported(priv)) return -EOPNOTSUPP; - spin_lock_irqsave(&priv->fpe_cfg.lock, flags); - - state->max_verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS; - state->verify_enabled = priv->fpe_cfg.verify_enabled; - state->pmac_enabled = priv->fpe_cfg.pmac_enabled; - state->verify_time = priv->fpe_cfg.verify_time; - state->tx_enabled = priv->fpe_cfg.tx_enabled; - state->verify_status = priv->fpe_cfg.status; state->rx_min_frag_size = ETH_ZLEN; - - /* FPE active if common tx_enabled and - * (verification success or disabled(forced)) - */ - if (state->tx_enabled && - (state->verify_status == ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED || - state->verify_status == ETHTOOL_MM_VERIFY_STATUS_DISABLED)) - state->tx_active = true; - else - state->tx_active = false; - frag_size = stmmac_fpe_get_add_frag_size(priv); state->tx_min_frag_size = ethtool_mm_frag_size_add_to_min(frag_size); - spin_unlock_irqrestore(&priv->fpe_cfg.lock, flags); + ethtool_mmsv_get_mm(&priv->fpe_cfg.mmsv, state); return 0; } @@ -1248,8 +1066,6 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, struct netlink_ext_ack *extack) { struct stmmac_priv *priv = netdev_priv(ndev); - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; - unsigned long flags; u32 frag_size; int err; @@ -1258,23 +1074,8 @@ static int stmmac_set_mm(struct net_device *ndev, struct ethtool_mm_cfg *cfg, if (err) return err; - /* Wait for the verification that's currently in progress to finish */ - timer_shutdown_sync(&fpe_cfg->verify_timer); - - spin_lock_irqsave(&fpe_cfg->lock, flags); - - fpe_cfg->verify_enabled = cfg->verify_enabled; - fpe_cfg->pmac_enabled = cfg->pmac_enabled; - fpe_cfg->verify_time = cfg->verify_time; - fpe_cfg->tx_enabled = cfg->tx_enabled; - - if (!cfg->verify_enabled) - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; - stmmac_fpe_set_add_frag_size(priv, frag_size); - stmmac_fpe_apply(priv); - - spin_unlock_irqrestore(&fpe_cfg->lock, flags); + ethtool_mmsv_set_mm(&priv->fpe_cfg.mmsv, cfg); return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c index 3a4bee029c7f..c54c70224351 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.c @@ -27,12 +27,6 @@ #define STMMAC_MAC_FPE_CTRL_STS_SVER BIT(1) #define STMMAC_MAC_FPE_CTRL_STS_EFPE BIT(0) -/* FPE link-partner hand-shaking mPacket type */ -enum stmmac_mpacket_type { - MPACKET_VERIFY = 0, - MPACKET_RESPONSE = 1, -}; - struct stmmac_fpe_reg { const u32 mac_fpe_reg; /* offset of MAC_FPE_CTRL_STS */ const u32 mtl_fpe_reg; /* offset of MTL_FPE_CTRL_STS */ @@ -48,10 +42,10 @@ bool stmmac_fpe_supported(struct stmmac_priv *priv) priv->hw->mac->fpe_map_preemption_class; } -static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable, - bool pmac_enable) +static void stmmac_fpe_configure_tx(struct ethtool_mmsv *mmsv, bool tx_enable) { - struct stmmac_fpe_cfg *cfg = &priv->fpe_cfg; + struct stmmac_fpe_cfg *cfg = container_of(mmsv, struct stmmac_fpe_cfg, mmsv); + struct stmmac_priv *priv = container_of(cfg, struct stmmac_priv, fpe_cfg); const struct stmmac_fpe_reg *reg = cfg->reg; u32 num_rxq = priv->plat->rx_queues_to_use; void __iomem *ioaddr = priv->ioaddr; @@ -68,7 +62,18 @@ static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable, cfg->fpe_csr = 0; } writel(cfg->fpe_csr, ioaddr + reg->mac_fpe_reg); +} + +static void stmmac_fpe_configure_pmac(struct ethtool_mmsv *mmsv, bool pmac_enable) +{ + struct stmmac_fpe_cfg *cfg = container_of(mmsv, struct stmmac_fpe_cfg, mmsv); + struct stmmac_priv *priv = container_of(cfg, struct stmmac_priv, fpe_cfg); + const struct stmmac_fpe_reg *reg = cfg->reg; + void __iomem *ioaddr = priv->ioaddr; + unsigned long flags; + u32 value; + spin_lock_irqsave(&priv->hw->irq_ctrl_lock, flags); value = readl(ioaddr + reg->int_en_reg); if (pmac_enable) { @@ -83,49 +88,48 @@ static void stmmac_fpe_configure(struct stmmac_priv *priv, bool tx_enable, } writel(value, ioaddr + reg->int_en_reg); + spin_unlock_irqrestore(&priv->hw->irq_ctrl_lock, flags); } -static void stmmac_fpe_send_mpacket(struct stmmac_priv *priv, - enum stmmac_mpacket_type type) +static void stmmac_fpe_send_mpacket(struct ethtool_mmsv *mmsv, + enum ethtool_mpacket type) { - const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; + struct stmmac_fpe_cfg *cfg = container_of(mmsv, struct stmmac_fpe_cfg, mmsv); + struct stmmac_priv *priv = container_of(cfg, struct stmmac_priv, fpe_cfg); + const struct stmmac_fpe_reg *reg = cfg->reg; void __iomem *ioaddr = priv->ioaddr; - u32 value = priv->fpe_cfg.fpe_csr; + u32 value = cfg->fpe_csr; - if (type == MPACKET_VERIFY) + if (type == ETHTOOL_MPACKET_VERIFY) value |= STMMAC_MAC_FPE_CTRL_STS_SVER; - else if (type == MPACKET_RESPONSE) + else if (type == ETHTOOL_MPACKET_RESPONSE) value |= STMMAC_MAC_FPE_CTRL_STS_SRSP; writel(value, ioaddr + reg->mac_fpe_reg); } +static const struct ethtool_mmsv_ops stmmac_mmsv_ops = { + .configure_tx = stmmac_fpe_configure_tx, + .configure_pmac = stmmac_fpe_configure_pmac, + .send_mpacket = stmmac_fpe_send_mpacket, +}; + static void stmmac_fpe_event_status(struct stmmac_priv *priv, int status) { struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; + struct ethtool_mmsv *mmsv = &fpe_cfg->mmsv; - /* This is interrupt context, just spin_lock() */ - spin_lock(&fpe_cfg->lock); - - if (!fpe_cfg->pmac_enabled || status == FPE_EVENT_UNKNOWN) - goto unlock_out; + if (status == FPE_EVENT_UNKNOWN) + return; - /* LP has sent verify mPacket */ if ((status & FPE_EVENT_RVER) == FPE_EVENT_RVER) - stmmac_fpe_send_mpacket(priv, MPACKET_RESPONSE); + ethtool_mmsv_event_handle(mmsv, ETHTOOL_MMSV_LP_SENT_VERIFY_MPACKET); - /* Local has sent verify mPacket */ - if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER && - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_VERIFYING; + if ((status & FPE_EVENT_TVER) == FPE_EVENT_TVER) + ethtool_mmsv_event_handle(mmsv, ETHTOOL_MMSV_LD_SENT_VERIFY_MPACKET); - /* LP has sent response mPacket */ - if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP && - fpe_cfg->status == ETHTOOL_MM_VERIFY_STATUS_VERIFYING) - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED; - -unlock_out: - spin_unlock(&fpe_cfg->lock); + if ((status & FPE_EVENT_RRSP) == FPE_EVENT_RRSP) + ethtool_mmsv_event_handle(mmsv, ETHTOOL_MMSV_LP_SENT_RESPONSE_MPACKET); } void stmmac_fpe_irq_status(struct stmmac_priv *priv) @@ -164,119 +168,16 @@ void stmmac_fpe_irq_status(struct stmmac_priv *priv) stmmac_fpe_event_status(priv, status); } -/** - * stmmac_fpe_verify_timer - Timer for MAC Merge verification - * @t: timer_list struct containing private info - * - * Verify the MAC Merge capability in the local TX direction, by - * transmitting Verify mPackets up to 3 times. Wait until link - * partner responds with a Response mPacket, otherwise fail. - */ -static void stmmac_fpe_verify_timer(struct timer_list *t) -{ - struct stmmac_fpe_cfg *fpe_cfg = from_timer(fpe_cfg, t, verify_timer); - struct stmmac_priv *priv = container_of(fpe_cfg, struct stmmac_priv, - fpe_cfg); - unsigned long flags; - bool rearm = false; - - spin_lock_irqsave(&fpe_cfg->lock, flags); - - switch (fpe_cfg->status) { - case ETHTOOL_MM_VERIFY_STATUS_INITIAL: - case ETHTOOL_MM_VERIFY_STATUS_VERIFYING: - if (fpe_cfg->verify_retries != 0) { - stmmac_fpe_send_mpacket(priv, MPACKET_VERIFY); - rearm = true; - } else { - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_FAILED; - } - - fpe_cfg->verify_retries--; - break; - - case ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED: - stmmac_fpe_configure(priv, true, true); - break; - - default: - break; - } - - if (rearm) { - mod_timer(&fpe_cfg->verify_timer, - jiffies + msecs_to_jiffies(fpe_cfg->verify_time)); - } - - spin_unlock_irqrestore(&fpe_cfg->lock, flags); -} - -static void stmmac_fpe_verify_timer_arm(struct stmmac_fpe_cfg *fpe_cfg) -{ - if (fpe_cfg->pmac_enabled && fpe_cfg->tx_enabled && - fpe_cfg->verify_enabled && - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_FAILED && - fpe_cfg->status != ETHTOOL_MM_VERIFY_STATUS_SUCCEEDED) { - timer_setup(&fpe_cfg->verify_timer, stmmac_fpe_verify_timer, 0); - mod_timer(&fpe_cfg->verify_timer, jiffies); - } -} - void stmmac_fpe_init(struct stmmac_priv *priv) { - priv->fpe_cfg.verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; - priv->fpe_cfg.verify_time = STMMAC_FPE_MM_MAX_VERIFY_TIME_MS; - priv->fpe_cfg.status = ETHTOOL_MM_VERIFY_STATUS_DISABLED; - timer_setup(&priv->fpe_cfg.verify_timer, stmmac_fpe_verify_timer, 0); - spin_lock_init(&priv->fpe_cfg.lock); + ethtool_mmsv_init(&priv->fpe_cfg.mmsv, priv->dev, + &stmmac_mmsv_ops); if ((!priv->fpe_cfg.reg || !priv->hw->mac->fpe_map_preemption_class) && priv->dma_cap.fpesel) dev_info(priv->device, "FPE is not supported by driver.\n"); } -void stmmac_fpe_apply(struct stmmac_priv *priv) -{ - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; - - /* If verification is disabled, configure FPE right away. - * Otherwise let the timer code do it. - */ - if (!fpe_cfg->verify_enabled) { - stmmac_fpe_configure(priv, fpe_cfg->tx_enabled, - fpe_cfg->pmac_enabled); - } else { - fpe_cfg->status = ETHTOOL_MM_VERIFY_STATUS_INITIAL; - fpe_cfg->verify_retries = STMMAC_FPE_MM_MAX_VERIFY_RETRIES; - - if (netif_running(priv->dev)) - stmmac_fpe_verify_timer_arm(fpe_cfg); - } -} - -void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up) -{ - struct stmmac_fpe_cfg *fpe_cfg = &priv->fpe_cfg; - unsigned long flags; - - timer_shutdown_sync(&fpe_cfg->verify_timer); - - spin_lock_irqsave(&fpe_cfg->lock, flags); - - if (is_up && fpe_cfg->pmac_enabled) { - /* VERIFY process requires pmac enabled when NIC comes up */ - stmmac_fpe_configure(priv, false, true); - - /* New link => maybe new partner => new verification process */ - stmmac_fpe_apply(priv); - } else { - /* No link => turn off EFPE */ - stmmac_fpe_configure(priv, false, false); - } - - spin_unlock_irqrestore(&fpe_cfg->lock, flags); -} - int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv) { const struct stmmac_fpe_reg *reg = priv->fpe_cfg.reg; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h index b884eac7142d..3fc46acf7001 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_fpe.h @@ -9,15 +9,10 @@ #include <linux/types.h> #include <linux/netdevice.h> -#define STMMAC_FPE_MM_MAX_VERIFY_RETRIES 3 -#define STMMAC_FPE_MM_MAX_VERIFY_TIME_MS 128 - struct stmmac_priv; -void stmmac_fpe_link_state_handle(struct stmmac_priv *priv, bool is_up); bool stmmac_fpe_supported(struct stmmac_priv *priv); void stmmac_fpe_init(struct stmmac_priv *priv); -void stmmac_fpe_apply(struct stmmac_priv *priv); void stmmac_fpe_irq_status(struct stmmac_priv *priv); int stmmac_fpe_get_add_frag_size(struct stmmac_priv *priv); void stmmac_fpe_set_add_frag_size(struct stmmac_priv *priv, u32 add_frag_size); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c index e2840fa241f2..bb110124f21e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c @@ -135,7 +135,6 @@ static int init_systime(void __iomem *ioaddr, u32 sec, u32 nsec) static int config_addend(void __iomem *ioaddr, u32 addend) { u32 value; - int limit; writel(addend, ioaddr + PTP_TAR); /* issue command to update the addend value */ @@ -144,23 +143,15 @@ static int config_addend(void __iomem *ioaddr, u32 addend) writel(value, ioaddr + PTP_TCR); /* wait for present addend update to complete */ - limit = 10; - while (limit--) { - if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSADDREG)) - break; - mdelay(10); - } - if (limit < 0) - return -EBUSY; - - return 0; + return readl_poll_timeout_atomic(ioaddr + PTP_TCR, value, + !(value & PTP_TCR_TSADDREG), + 10, 100000); } static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, int add_sub, int gmac4) { u32 value; - int limit; if (add_sub) { /* If the new sec value needs to be subtracted with @@ -187,16 +178,9 @@ static int adjust_systime(void __iomem *ioaddr, u32 sec, u32 nsec, writel(value, ioaddr + PTP_TCR); /* wait for present system time adjust/update to complete */ - limit = 10; - while (limit--) { - if (!(readl(ioaddr + PTP_TCR) & PTP_TCR_TSUPDT)) - break; - mdelay(10); - } - if (limit < 0) - return -EBUSY; - - return 0; + return readl_poll_timeout_atomic(ioaddr + PTP_TCR, value, + !(value & PTP_TCR_TSUPDT), + 10, 100000); } static void get_systime(void __iomem *ioaddr, u64 *systime) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_libpci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_libpci.c new file mode 100644 index 000000000000..5c5dd502f79a --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_libpci.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PCI bus helpers for STMMAC driver + * Copyright (C) 2025 Yao Zi <ziyao@disroot.org> + */ + +#include <linux/device.h> +#include <linux/pci.h> + +#include "stmmac_libpci.h" + +int stmmac_pci_plat_suspend(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + ret = pci_save_state(pdev); + if (ret) + return ret; + + pci_disable_device(pdev); + pci_wake_from_d3(pdev, true); + + return 0; +} +EXPORT_SYMBOL_GPL(stmmac_pci_plat_suspend); + +int stmmac_pci_plat_resume(struct device *dev, void *bsp_priv) +{ + struct pci_dev *pdev = to_pci_dev(dev); + int ret; + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + ret = pci_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + return 0; +} +EXPORT_SYMBOL_GPL(stmmac_pci_plat_resume); + +MODULE_DESCRIPTION("STMMAC PCI helper library"); +MODULE_AUTHOR("Yao Zi <ziyao@disroot.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_libpci.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_libpci.h new file mode 100644 index 000000000000..71553184f982 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_libpci.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025 Yao Zi <ziyao@disroot.org> + */ + +#ifndef __STMMAC_LIBPCI_H__ +#define __STMMAC_LIBPCI_H__ + +int stmmac_pci_plat_suspend(struct device *dev, void *bsp_priv); +int stmmac_pci_plat_resume(struct device *dev, void *bsp_priv); + +#endif /* __STMMAC_LIBPCI_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 59d07d0d3369..b3730312aeed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -29,6 +29,7 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> #include <linux/pm_runtime.h> +#include <linux/pm_wakeirq.h> #include <linux/prefetch.h> #include <linux/pinctrl/consumer.h> #ifdef CONFIG_DEBUG_FS @@ -39,12 +40,14 @@ #include <linux/phylink.h> #include <linux/udp.h> #include <linux/bpf_trace.h> +#include <net/devlink.h> #include <net/page_pool/helpers.h> #include <net/pkt_cls.h> #include <net/xdp_sock_drv.h> #include "stmmac_ptp.h" #include "stmmac_fpe.h" #include "stmmac.h" +#include "stmmac_pcs.h" #include "stmmac_xdp.h" #include <linux/reset.h> #include <linux/of_mdio.h> @@ -56,8 +59,7 @@ * with fine resolution and binary rollover. This avoid non-monotonic behavior * (clock jumps) when changing timestamping settings at runtime. */ -#define STMMAC_HWTS_ACTIVE (PTP_TCR_TSENA | PTP_TCR_TSCFUPDT | \ - PTP_TCR_TSCTRLSSR) +#define STMMAC_HWTS_ACTIVE (PTP_TCR_TSENA | PTP_TCR_TSCTRLSSR) #define STMMAC_ALIGN(x) ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16) #define TSO_MAX_BUFF_SIZE (SZ_16K - 1) @@ -87,6 +89,7 @@ MODULE_PARM_DESC(phyaddr, "Physical device address"); #define STMMAC_XDP_CONSUMED BIT(0) #define STMMAC_XDP_TX BIT(1) #define STMMAC_XDP_REDIRECT BIT(2) +#define STMMAC_XSK_CONSUMED BIT(3) static int flow_ctrl = 0xdead; module_param(flow_ctrl, int, 0644); @@ -146,37 +149,14 @@ static void stmmac_exit_fs(struct net_device *dev); #define STMMAC_COAL_TIMER(x) (ns_to_ktime((x) * NSEC_PER_USEC)) -int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled) -{ - int ret = 0; - - if (enabled) { - ret = clk_prepare_enable(priv->plat->stmmac_clk); - if (ret) - return ret; - ret = clk_prepare_enable(priv->plat->pclk); - if (ret) { - clk_disable_unprepare(priv->plat->stmmac_clk); - return ret; - } - if (priv->plat->clks_config) { - ret = priv->plat->clks_config(priv->plat->bsp_priv, enabled); - if (ret) { - clk_disable_unprepare(priv->plat->stmmac_clk); - clk_disable_unprepare(priv->plat->pclk); - return ret; - } - } - } else { - clk_disable_unprepare(priv->plat->stmmac_clk); - clk_disable_unprepare(priv->plat->pclk); - if (priv->plat->clks_config) - priv->plat->clks_config(priv->plat->bsp_priv, enabled); - } +struct stmmac_devlink_priv { + struct stmmac_priv *stmmac_priv; +}; - return ret; -} -EXPORT_SYMBOL_GPL(stmmac_bus_clks_config); +enum stmmac_dl_param_id { + STMMAC_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX, + STMMAC_DEVLINK_PARAM_ID_TS_COARSE, +}; /** * stmmac_set_clk_tx_rate() - set the clock rate for the MAC transmit clock @@ -211,6 +191,44 @@ int stmmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i, EXPORT_SYMBOL_GPL(stmmac_set_clk_tx_rate); /** + * stmmac_axi_blen_to_mask() - convert a burst length array to reg value + * @regval: pointer to a u32 for the resulting register value + * @blen: pointer to an array of u32 containing the burst length values in bytes + * @len: the number of entries in the @blen array + */ +void stmmac_axi_blen_to_mask(u32 *regval, const u32 *blen, size_t len) +{ + size_t i; + u32 val; + + for (val = i = 0; i < len; i++) { + u32 burst = blen[i]; + + /* Burst values of zero must be skipped. */ + if (!burst) + continue; + + /* The valid range for the burst length is 4 to 256 inclusive, + * and it must be a power of two. + */ + if (burst < 4 || burst > 256 || !is_power_of_2(burst)) { + pr_err("stmmac: invalid burst length %u at index %zu\n", + burst, i); + continue; + } + + /* Since burst is a power of two, and the register field starts + * with burst = 4, shift right by two bits so bit 0 of the field + * corresponds with the minimum value. + */ + val |= burst >> 2; + } + + *regval = FIELD_PREP(DMA_AXI_BLEN_MASK, val); +} +EXPORT_SYMBOL_GPL(stmmac_axi_blen_to_mask); + +/** * stmmac_verify_args - verify the driver parameters. * Description: it checks the driver parameters and set a default in case of * errors. @@ -312,77 +330,6 @@ static void stmmac_global_err(struct stmmac_priv *priv) stmmac_service_event_schedule(priv); } -/** - * stmmac_clk_csr_set - dynamically set the MDC clock - * @priv: driver private structure - * Description: this is to dynamically set the MDC clock according to the csr - * clock input. - * Note: - * If a specific clk_csr value is passed from the platform - * this means that the CSR Clock Range selection cannot be - * changed at run-time and it is fixed (as reported in the driver - * documentation). Viceversa the driver will try to set the MDC - * clock dynamically according to the actual clock input. - */ -static void stmmac_clk_csr_set(struct stmmac_priv *priv) -{ - unsigned long clk_rate; - - clk_rate = clk_get_rate(priv->plat->stmmac_clk); - - /* Platform provided default clk_csr would be assumed valid - * for all other cases except for the below mentioned ones. - * For values higher than the IEEE 802.3 specified frequency - * we can not estimate the proper divider as it is not known - * the frequency of clk_csr_i. So we do not change the default - * divider. - */ - if (!(priv->clk_csr & MAC_CSR_H_FRQ_MASK)) { - if (clk_rate < CSR_F_35M) - priv->clk_csr = STMMAC_CSR_20_35M; - else if ((clk_rate >= CSR_F_35M) && (clk_rate < CSR_F_60M)) - priv->clk_csr = STMMAC_CSR_35_60M; - else if ((clk_rate >= CSR_F_60M) && (clk_rate < CSR_F_100M)) - priv->clk_csr = STMMAC_CSR_60_100M; - else if ((clk_rate >= CSR_F_100M) && (clk_rate < CSR_F_150M)) - priv->clk_csr = STMMAC_CSR_100_150M; - else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) - priv->clk_csr = STMMAC_CSR_150_250M; - else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M)) - priv->clk_csr = STMMAC_CSR_250_300M; - else if ((clk_rate >= CSR_F_300M) && (clk_rate < CSR_F_500M)) - priv->clk_csr = STMMAC_CSR_300_500M; - else if ((clk_rate >= CSR_F_500M) && (clk_rate < CSR_F_800M)) - priv->clk_csr = STMMAC_CSR_500_800M; - } - - if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I) { - if (clk_rate > 160000000) - priv->clk_csr = 0x03; - else if (clk_rate > 80000000) - priv->clk_csr = 0x02; - else if (clk_rate > 40000000) - priv->clk_csr = 0x01; - else - priv->clk_csr = 0; - } - - if (priv->plat->has_xgmac) { - if (clk_rate > 400000000) - priv->clk_csr = 0x5; - else if (clk_rate > 350000000) - priv->clk_csr = 0x4; - else if (clk_rate > 300000000) - priv->clk_csr = 0x3; - else if (clk_rate > 250000000) - priv->clk_csr = 0x2; - else if (clk_rate > 150000000) - priv->clk_csr = 0x1; - else - priv->clk_csr = 0x0; - } -} - static void print_pkt(unsigned char *buf, int len) { pr_debug("len = %d byte, buf addr: 0x%p\n", len, buf); @@ -481,7 +428,7 @@ static void stmmac_stop_sw_lpi(struct stmmac_priv *priv) */ static void stmmac_eee_ctrl_timer(struct timer_list *t) { - struct stmmac_priv *priv = from_timer(priv, t, eee_ctrl_timer); + struct stmmac_priv *priv = timer_container_of(priv, t, eee_ctrl_timer); stmmac_try_to_start_sw_lpi(priv); } @@ -547,7 +494,7 @@ static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p, if (!priv->hwts_rx_en) return; /* For GMAC4, the valid timestamp is from CTX next desc. */ - if (priv->plat->has_gmac4 || priv->plat->has_xgmac) + if (dwmac_is_xmac(priv->plat->core_type)) desc = np; /* Check if timestamp is available */ @@ -565,21 +512,49 @@ static void stmmac_get_rx_hwtstamp(struct stmmac_priv *priv, struct dma_desc *p, } } +static void stmmac_update_subsecond_increment(struct stmmac_priv *priv) +{ + bool xmac = dwmac_is_xmac(priv->plat->core_type); + u32 sec_inc = 0; + u64 temp = 0; + + stmmac_config_hw_tstamping(priv, priv->ptpaddr, priv->systime_flags); + + /* program Sub Second Increment reg */ + stmmac_config_sub_second_increment(priv, priv->ptpaddr, + priv->plat->clk_ptp_rate, + xmac, &sec_inc); + temp = div_u64(1000000000ULL, sec_inc); + + /* Store sub second increment for later use */ + priv->sub_second_inc = sec_inc; + + /* calculate default added value: + * formula is : + * addend = (2^32)/freq_div_ratio; + * where, freq_div_ratio = 1e9ns/sec_inc + */ + temp = (u64)(temp << 32); + priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate); + stmmac_config_addend(priv, priv->ptpaddr, priv->default_addend); +} + /** * stmmac_hwtstamp_set - control hardware timestamping. * @dev: device pointer. - * @ifr: An IOCTL specific structure, that can contain a pointer to - * a proprietary structure used to pass information to the driver. + * @config: the timestamping configuration. + * @extack: netlink extended ack structure for error reporting. * Description: * This function configures the MAC to enable/disable both outgoing(TX) * and incoming(RX) packets time stamping based on user input. * Return Value: * 0 on success and an appropriate -ve integer on failure. */ -static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) +static int stmmac_hwtstamp_set(struct net_device *dev, + struct kernel_hwtstamp_config *config, + struct netlink_ext_ack *extack) { struct stmmac_priv *priv = netdev_priv(dev); - struct hwtstamp_config config; u32 ptp_v2 = 0; u32 tstamp_all = 0; u32 ptp_over_ipv4_udp = 0; @@ -590,34 +565,36 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) u32 ts_event_en = 0; if (!(priv->dma_cap.time_stamp || priv->adv_ts)) { - netdev_alert(priv->dev, "No support for HW time stamping\n"); + NL_SET_ERR_MSG_MOD(extack, "No support for HW time stamping"); priv->hwts_tx_en = 0; priv->hwts_rx_en = 0; return -EOPNOTSUPP; } - if (copy_from_user(&config, ifr->ifr_data, - sizeof(config))) - return -EFAULT; + if (!netif_running(dev)) { + NL_SET_ERR_MSG_MOD(extack, + "Cannot change timestamping configuration while down"); + return -ENODEV; + } netdev_dbg(priv->dev, "%s config flags:0x%x, tx_type:0x%x, rx_filter:0x%x\n", - __func__, config.flags, config.tx_type, config.rx_filter); + __func__, config->flags, config->tx_type, config->rx_filter); - if (config.tx_type != HWTSTAMP_TX_OFF && - config.tx_type != HWTSTAMP_TX_ON) + if (config->tx_type != HWTSTAMP_TX_OFF && + config->tx_type != HWTSTAMP_TX_ON) return -ERANGE; if (priv->adv_ts) { - switch (config.rx_filter) { + switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: /* time stamp no incoming packet at all */ - config.rx_filter = HWTSTAMP_FILTER_NONE; + config->rx_filter = HWTSTAMP_FILTER_NONE; break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: /* PTP v1, UDP, any kind of event packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; /* 'xmac' hardware can support Sync, Pdelay_Req and * Pdelay_resp by setting bit14 and bits17/16 to 01 * This leaves Delay_Req timestamps out. @@ -631,7 +608,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: /* PTP v1, UDP, Sync packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; + config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_SYNC; /* take time stamp for SYNC messages only */ ts_event_en = PTP_TCR_TSEVNTENA; @@ -641,7 +618,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: /* PTP v1, UDP, Delay_req packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; + config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ; /* take time stamp for Delay_Req messages only */ ts_master_en = PTP_TCR_TSMSTRENA; ts_event_en = PTP_TCR_TSEVNTENA; @@ -652,7 +629,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: /* PTP v2, UDP, any kind of event packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for all event messages */ snap_type_sel = PTP_TCR_SNAPTYPSEL_1; @@ -663,7 +640,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: /* PTP v2, UDP, Sync packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_SYNC; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for SYNC messages only */ ts_event_en = PTP_TCR_TSEVNTENA; @@ -674,7 +651,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: /* PTP v2, UDP, Delay_req packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for Delay_Req messages only */ ts_master_en = PTP_TCR_TSMSTRENA; @@ -686,7 +663,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_EVENT: /* PTP v2/802.AS1 any layer, any kind of event packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; ptp_v2 = PTP_TCR_TSVER2ENA; snap_type_sel = PTP_TCR_SNAPTYPSEL_1; if (priv->synopsys_id < DWMAC_CORE_4_10) @@ -698,7 +675,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_SYNC: /* PTP v2/802.AS1, any layer, Sync packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for SYNC messages only */ ts_event_en = PTP_TCR_TSEVNTENA; @@ -710,7 +687,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: /* PTP v2/802.AS1, any layer, Delay_req packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ; ptp_v2 = PTP_TCR_TSVER2ENA; /* take time stamp for Delay_Req messages only */ ts_master_en = PTP_TCR_TSMSTRENA; @@ -724,7 +701,7 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) case HWTSTAMP_FILTER_NTP_ALL: case HWTSTAMP_FILTER_ALL: /* time stamp any incoming packet */ - config.rx_filter = HWTSTAMP_FILTER_ALL; + config->rx_filter = HWTSTAMP_FILTER_ALL; tstamp_all = PTP_TCR_TSENALL; break; @@ -732,20 +709,22 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) return -ERANGE; } } else { - switch (config.rx_filter) { + switch (config->rx_filter) { case HWTSTAMP_FILTER_NONE: - config.rx_filter = HWTSTAMP_FILTER_NONE; + config->rx_filter = HWTSTAMP_FILTER_NONE; break; default: /* PTP v1, UDP, any kind of event packet */ - config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; break; } } - priv->hwts_rx_en = ((config.rx_filter == HWTSTAMP_FILTER_NONE) ? 0 : 1); - priv->hwts_tx_en = config.tx_type == HWTSTAMP_TX_ON; + priv->hwts_rx_en = config->rx_filter != HWTSTAMP_FILTER_NONE; + priv->hwts_tx_en = config->tx_type == HWTSTAMP_TX_ON; priv->systime_flags = STMMAC_HWTS_ACTIVE; + if (!priv->tsfupdt_coarse) + priv->systime_flags |= PTP_TCR_TSCFUPDT; if (priv->hwts_tx_en || priv->hwts_rx_en) { priv->systime_flags |= tstamp_all | ptp_v2 | @@ -756,31 +735,30 @@ static int stmmac_hwtstamp_set(struct net_device *dev, struct ifreq *ifr) stmmac_config_hw_tstamping(priv, priv->ptpaddr, priv->systime_flags); - memcpy(&priv->tstamp_config, &config, sizeof(config)); + priv->tstamp_config = *config; - return copy_to_user(ifr->ifr_data, &config, - sizeof(config)) ? -EFAULT : 0; + return 0; } /** * stmmac_hwtstamp_get - read hardware timestamping. * @dev: device pointer. - * @ifr: An IOCTL specific structure, that can contain a pointer to - * a proprietary structure used to pass information to the driver. + * @config: the timestamping configuration. * Description: * This function obtain the current hardware timestamping settings * as requested. */ -static int stmmac_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) +static int stmmac_hwtstamp_get(struct net_device *dev, + struct kernel_hwtstamp_config *config) { struct stmmac_priv *priv = netdev_priv(dev); - struct hwtstamp_config *config = &priv->tstamp_config; if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) return -EOPNOTSUPP; - return copy_to_user(ifr->ifr_data, config, - sizeof(*config)) ? -EFAULT : 0; + *config = priv->tstamp_config; + + return 0; } /** @@ -793,36 +771,20 @@ static int stmmac_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) * Will be rerun after resuming from suspend, case in which the timestamping * flags updated by stmmac_hwtstamp_set() also need to be restored. */ -int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags) +static int stmmac_init_tstamp_counter(struct stmmac_priv *priv, + u32 systime_flags) { - bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; struct timespec64 now; - u32 sec_inc = 0; - u64 temp = 0; - if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) - return -EOPNOTSUPP; + if (!priv->plat->clk_ptp_rate) { + netdev_err(priv->dev, "Invalid PTP clock rate"); + return -EINVAL; + } stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags); priv->systime_flags = systime_flags; - /* program Sub Second Increment reg */ - stmmac_config_sub_second_increment(priv, priv->ptpaddr, - priv->plat->clk_ptp_rate, - xmac, &sec_inc); - temp = div_u64(1000000000ULL, sec_inc); - - /* Store sub second increment for later use */ - priv->sub_second_inc = sec_inc; - - /* calculate default added value: - * formula is : - * addend = (2^32)/freq_div_ratio; - * where, freq_div_ratio = 1e9ns/sec_inc - */ - temp = (u64)(temp << 32); - priv->default_addend = div_u64(temp, priv->plat->clk_ptp_rate); - stmmac_config_addend(priv, priv->ptpaddr, priv->default_addend); + stmmac_update_subsecond_increment(priv); /* initialize system time */ ktime_get_real_ts64(&now); @@ -832,26 +794,33 @@ int stmmac_init_tstamp_counter(struct stmmac_priv *priv, u32 systime_flags) return 0; } -EXPORT_SYMBOL_GPL(stmmac_init_tstamp_counter); /** - * stmmac_init_ptp - init PTP + * stmmac_init_timestamping - initialise timestamping * @priv: driver private structure * Description: this is to verify if the HW supports the PTPv1 or PTPv2. * This is done by looking at the HW cap. register. * This function also registers the ptp driver. */ -static int stmmac_init_ptp(struct stmmac_priv *priv) +static int stmmac_init_timestamping(struct stmmac_priv *priv) { - bool xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; + bool xmac = dwmac_is_xmac(priv->plat->core_type); int ret; if (priv->plat->ptp_clk_freq_config) priv->plat->ptp_clk_freq_config(priv); - ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE); - if (ret) + if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) { + netdev_info(priv->dev, "PTP not supported by HW\n"); + return -EOPNOTSUPP; + } + + ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE | + PTP_TCR_TSCFUPDT); + if (ret) { + netdev_warn(priv->dev, "PTP init failed\n"); return ret; + } priv->adv_ts = 0; /* Check if adv_ts can be enabled for dwmac 4.x / xgmac core */ @@ -877,10 +846,24 @@ static int stmmac_init_ptp(struct stmmac_priv *priv) return 0; } +static void stmmac_setup_ptp(struct stmmac_priv *priv) +{ + int ret; + + ret = clk_prepare_enable(priv->plat->clk_ptp_ref); + if (ret < 0) + netdev_warn(priv->dev, + "failed to enable PTP reference clock: %pe\n", + ERR_PTR(ret)); + + if (stmmac_init_timestamping(priv) == 0) + stmmac_ptp_register(priv); +} + static void stmmac_release_ptp(struct stmmac_priv *priv) { - clk_disable_unprepare(priv->plat->clk_ptp_ref); stmmac_ptp_unregister(priv); + clk_disable_unprepare(priv->plat->clk_ptp_ref); } /** @@ -927,6 +910,13 @@ static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config, return pcs; } + /* The PCS control register is only relevant for SGMII, TBI and RTBI + * modes. We no longer support TBI or RTBI, so only configure this + * register when operating in SGMII mode with the integrated PCS. + */ + if (priv->hw->pcs & STMMAC_PCS_SGMII && priv->integrated_pcs) + return &priv->integrated_pcs->pcs; + return NULL; } @@ -936,6 +926,18 @@ static void stmmac_mac_config(struct phylink_config *config, unsigned int mode, /* Nothing to do, xpcs_config() handles everything */ } +static int stmmac_mac_finish(struct phylink_config *config, unsigned int mode, + phy_interface_t interface) +{ + struct net_device *ndev = to_net_dev(config->dev); + struct stmmac_priv *priv = netdev_priv(ndev); + + if (priv->plat->mac_finish) + priv->plat->mac_finish(ndev, priv->plat->bsp_priv, mode, interface); + + return 0; +} + static void stmmac_mac_link_down(struct phylink_config *config, unsigned int mode, phy_interface_t interface) { @@ -946,7 +948,7 @@ static void stmmac_mac_link_down(struct phylink_config *config, stmmac_set_eee_pls(priv, priv->hw, false); if (stmmac_fpe_supported(priv)) - stmmac_fpe_link_state_handle(priv, false); + ethtool_mmsv_link_state_handle(&priv->fpe_cfg.mmsv, false); } static void stmmac_mac_link_up(struct phylink_config *config, @@ -1055,8 +1057,8 @@ static void stmmac_mac_link_up(struct phylink_config *config, interface, speed); if (ret < 0) netdev_err(priv->dev, - "failed to configure transmit clock for %dMbps: %pe\n", - speed, ERR_PTR(ret)); + "failed to configure %s transmit clock for %dMbps: %pe\n", + phy_modes(interface), speed, ERR_PTR(ret)); } stmmac_mac_set(priv, priv->ioaddr, true); @@ -1064,7 +1066,7 @@ static void stmmac_mac_link_up(struct phylink_config *config, stmmac_set_eee_pls(priv, priv->hw, true); if (stmmac_fpe_supported(priv)) - stmmac_fpe_link_state_handle(priv, true); + ethtool_mmsv_link_state_handle(&priv->fpe_cfg.mmsv, true); if (priv->plat->flags & STMMAC_FLAG_HWTSTAMP_CORRECT_LATENCY) stmmac_hwtstamp_correct_latency(priv, priv); @@ -1130,14 +1132,16 @@ static int stmmac_mac_enable_tx_lpi(struct phylink_config *config, u32 timer, return 0; } -static int stmmac_mac_finish(struct phylink_config *config, unsigned int mode, - phy_interface_t interface) +static int stmmac_mac_wol_set(struct phylink_config *config, u32 wolopts, + const u8 *sopass) { - struct net_device *ndev = to_net_dev(config->dev); - struct stmmac_priv *priv = netdev_priv(ndev); + struct stmmac_priv *priv = netdev_priv(to_net_dev(config->dev)); - if (priv->plat->mac_finish) - priv->plat->mac_finish(ndev, priv->plat->bsp_priv, mode, interface); + device_set_wakeup_enable(priv->device, !!wolopts); + + mutex_lock(&priv->lock); + priv->wolopts = wolopts; + mutex_unlock(&priv->lock); return 0; } @@ -1146,11 +1150,12 @@ static const struct phylink_mac_ops stmmac_phylink_mac_ops = { .mac_get_caps = stmmac_mac_get_caps, .mac_select_pcs = stmmac_mac_select_pcs, .mac_config = stmmac_mac_config, + .mac_finish = stmmac_mac_finish, .mac_link_down = stmmac_mac_link_down, .mac_link_up = stmmac_mac_link_up, .mac_disable_tx_lpi = stmmac_mac_disable_tx_lpi, .mac_enable_tx_lpi = stmmac_mac_enable_tx_lpi, - .mac_finish = stmmac_mac_finish, + .mac_wol_set = stmmac_mac_wol_set, }; /** @@ -1162,18 +1167,26 @@ static const struct phylink_mac_ops stmmac_phylink_mac_ops = { */ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) { - int interface = priv->plat->mac_interface; - - if (priv->dma_cap.pcs) { - if ((interface == PHY_INTERFACE_MODE_RGMII) || - (interface == PHY_INTERFACE_MODE_RGMII_ID) || - (interface == PHY_INTERFACE_MODE_RGMII_RXID) || - (interface == PHY_INTERFACE_MODE_RGMII_TXID)) { - netdev_dbg(priv->dev, "PCS RGMII support enabled\n"); - priv->hw->pcs = STMMAC_PCS_RGMII; - } else if (interface == PHY_INTERFACE_MODE_SGMII) { - netdev_dbg(priv->dev, "PCS SGMII support enabled\n"); - priv->hw->pcs = STMMAC_PCS_SGMII; + int interface = priv->plat->phy_interface; + int speed = priv->plat->mac_port_sel_speed; + + if (priv->dma_cap.pcs && interface == PHY_INTERFACE_MODE_SGMII) { + netdev_dbg(priv->dev, "PCS SGMII support enabled\n"); + priv->hw->pcs = STMMAC_PCS_SGMII; + + switch (speed) { + case SPEED_10: + case SPEED_100: + case SPEED_1000: + priv->hw->reverse_sgmii_enable = true; + break; + + default: + dev_warn(priv->device, "invalid port speed\n"); + fallthrough; + case 0: + priv->hw->reverse_sgmii_enable = false; + break; } } } @@ -1189,13 +1202,19 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv) static int stmmac_init_phy(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); + int mode = priv->plat->phy_interface; struct fwnode_handle *phy_fwnode; struct fwnode_handle *fwnode; + struct ethtool_keee eee; int ret; if (!phylink_expects_phy(priv->phylink)) return 0; + if (priv->hw->xpcs && + xpcs_get_an_mode(priv->hw->xpcs, mode) == DW_AN_C73) + return 0; + fwnode = priv->plat->port_node; if (!fwnode) fwnode = dev_fwnode(priv->device); @@ -1229,49 +1248,48 @@ static int stmmac_init_phy(struct net_device *dev) ret = phylink_fwnode_phy_connect(priv->phylink, fwnode, 0); } - if (ret == 0) { - struct ethtool_keee eee; - - /* Configure phylib's copy of the LPI timer. Normally, - * phylink_config.lpi_timer_default would do this, but there is - * a chance that userspace could change the eee_timer setting - * via sysfs before the first open. Thus, preserve existing - * behaviour. - */ - if (!phylink_ethtool_get_eee(priv->phylink, &eee)) { - eee.tx_lpi_timer = priv->tx_lpi_timer; - phylink_ethtool_set_eee(priv->phylink, &eee); - } + if (ret) { + netdev_err(priv->dev, "cannot attach to PHY (error: %pe)\n", + ERR_PTR(ret)); + return ret; } - if (!priv->plat->pmt) { - struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; - - phylink_ethtool_get_wol(priv->phylink, &wol); - device_set_wakeup_capable(priv->device, !!wol.supported); - device_set_wakeup_enable(priv->device, !!wol.wolopts); + /* Configure phylib's copy of the LPI timer. Normally, + * phylink_config.lpi_timer_default would do this, but there is a + * chance that userspace could change the eee_timer setting via sysfs + * before the first open. Thus, preserve existing behaviour. + */ + if (!phylink_ethtool_get_eee(priv->phylink, &eee)) { + eee.tx_lpi_timer = priv->tx_lpi_timer; + phylink_ethtool_set_eee(priv->phylink, &eee); } - return ret; + return 0; } -static int stmmac_phy_setup(struct stmmac_priv *priv) +static int stmmac_phylink_setup(struct stmmac_priv *priv) { struct stmmac_mdio_bus_data *mdio_bus_data; - int mode = priv->plat->phy_interface; + struct phylink_config *config; struct fwnode_handle *fwnode; struct phylink_pcs *pcs; struct phylink *phylink; - priv->phylink_config.dev = &priv->dev->dev; - priv->phylink_config.type = PHYLINK_NETDEV; - priv->phylink_config.mac_managed_pm = true; + config = &priv->phylink_config; + + config->dev = &priv->dev->dev; + config->type = PHYLINK_NETDEV; + config->mac_managed_pm = true; /* Stmmac always requires an RX clock for hardware initialization */ - priv->phylink_config.mac_requires_rxc = true; + config->mac_requires_rxc = true; - if (!(priv->plat->flags & STMMAC_FLAG_RX_CLK_RUNS_IN_LPI)) - priv->phylink_config.eee_rx_clk_stop_enable = true; + /* Disable EEE RX clock stop to ensure VLAN register access works + * correctly. + */ + if (!(priv->plat->flags & STMMAC_FLAG_RX_CLK_RUNS_IN_LPI) && + !(priv->dev->features & NETIF_F_VLAN_FEATURES)) + config->eee_rx_clk_stop_enable = true; /* Set the default transmit clock stop bit based on the platform glue */ priv->tx_lpi_clk_stop = priv->plat->flags & @@ -1279,13 +1297,22 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) mdio_bus_data = priv->plat->mdio_bus_data; if (mdio_bus_data) - priv->phylink_config.default_an_inband = - mdio_bus_data->default_an_inband; + 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, + 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(config->supported_interfaces)) + __set_bit(priv->plat->phy_interface, + config->supported_interfaces); /* If we have an xpcs, it defines which PHY interfaces are supported. */ if (priv->hw->xpcs) @@ -1294,29 +1321,37 @@ static int stmmac_phy_setup(struct stmmac_priv *priv) pcs = priv->hw->phylink_pcs; if (pcs) - phy_interface_or(priv->phylink_config.supported_interfaces, - priv->phylink_config.supported_interfaces, + phy_interface_or(config->supported_interfaces, + config->supported_interfaces, pcs->supported_interfaces); if (priv->dma_cap.eee) { /* Assume all supported interfaces also support LPI */ - memcpy(priv->phylink_config.lpi_interfaces, - priv->phylink_config.supported_interfaces, - sizeof(priv->phylink_config.lpi_interfaces)); + memcpy(config->lpi_interfaces, config->supported_interfaces, + sizeof(config->lpi_interfaces)); /* All full duplex speeds above 100Mbps are supported */ - priv->phylink_config.lpi_capabilities = ~(MAC_1000FD - 1) | - MAC_100FD; - priv->phylink_config.lpi_timer_default = eee_timer * 1000; - priv->phylink_config.eee_enabled_default = true; + config->lpi_capabilities = ~(MAC_1000FD - 1) | MAC_100FD; + config->lpi_timer_default = eee_timer * 1000; + config->eee_enabled_default = true; + } + + config->wol_phy_speed_ctrl = true; + if (priv->plat->flags & STMMAC_FLAG_USE_PHY_WOL) { + config->wol_phy_legacy = true; + } else { + if (priv->dma_cap.pmt_remote_wake_up) + config->wol_mac_support |= WAKE_UCAST; + if (priv->dma_cap.pmt_magic_frame) + config->wol_mac_support |= WAKE_MAGIC; } fwnode = priv->plat->port_node; if (!fwnode) fwnode = dev_fwnode(priv->device); - phylink = phylink_create(&priv->phylink_config, fwnode, - mode, &stmmac_phylink_mac_ops); + phylink = phylink_create(config, fwnode, priv->plat->phy_interface, + &stmmac_phylink_mac_ops); if (IS_ERR(phylink)) return PTR_ERR(phylink); @@ -1400,9 +1435,9 @@ static unsigned int stmmac_rx_offset(struct stmmac_priv *priv) return NET_SKB_PAD; } -static int stmmac_set_bfsize(int mtu, int bufsize) +static int stmmac_set_bfsize(int mtu) { - int ret = bufsize; + int ret; if (mtu >= BUF_SIZE_8KiB) ret = BUF_SIZE_16KiB; @@ -1531,7 +1566,7 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, buf->page_offset = stmmac_rx_offset(priv); } - if (priv->sph && !buf->sec_page) { + if (priv->sph_active && !buf->sec_page) { buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp); if (!buf->sec_page) return -ENOMEM; @@ -2117,7 +2152,7 @@ static int __alloc_dma_rx_desc_resources(struct stmmac_priv *priv, pp_params.offset = stmmac_rx_offset(priv); pp_params.max_len = dma_conf->dma_buf_sz; - if (priv->sph) { + if (priv->sph_active) { pp_params.offset = 0; pp_params.max_len += stmmac_rx_offset(priv); } @@ -2458,7 +2493,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv) txfifosz = priv->dma_cap.tx_fifo_size; /* Split up the shared Tx/Rx FIFO memory on DW QoS Eth and DW XGMAC */ - if (priv->plat->has_gmac4 || priv->plat->has_xgmac) { + if (dwmac_is_xmac(priv->plat->core_type)) { rxfifosz /= rx_channels_count; txfifosz /= tx_channels_count; } @@ -2568,6 +2603,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; + bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported; struct xsk_buff_pool *pool = tx_q->xsk_pool; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc = NULL; @@ -2580,7 +2616,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) budget = min(budget, stmmac_tx_avail(priv, queue)); - while (budget-- > 0) { + for (; budget > 0; budget--) { struct stmmac_metadata_request meta_req; struct xsk_tx_metadata *meta = NULL; dma_addr_t dma_addr; @@ -2655,7 +2691,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) } stmmac_prepare_tx_desc(priv, tx_desc, 1, xdp_desc.len, - true, priv->mode, true, true, + csum, priv->mode, true, true, xdp_desc.len); stmmac_enable_dma_transmission(priv, priv->ioaddr, queue); @@ -3089,6 +3125,56 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv) } } +int stmmac_get_phy_intf_sel(phy_interface_t interface) +{ + int phy_intf_sel = -EINVAL; + + if (interface == PHY_INTERFACE_MODE_MII || + interface == PHY_INTERFACE_MODE_GMII) + phy_intf_sel = PHY_INTF_SEL_GMII_MII; + else if (phy_interface_mode_is_rgmii(interface)) + phy_intf_sel = PHY_INTF_SEL_RGMII; + else if (interface == PHY_INTERFACE_MODE_SGMII) + phy_intf_sel = PHY_INTF_SEL_SGMII; + else if (interface == PHY_INTERFACE_MODE_RMII) + phy_intf_sel = PHY_INTF_SEL_RMII; + else if (interface == PHY_INTERFACE_MODE_REVMII) + phy_intf_sel = PHY_INTF_SEL_REVMII; + + return phy_intf_sel; +} +EXPORT_SYMBOL_GPL(stmmac_get_phy_intf_sel); + +static int stmmac_prereset_configure(struct stmmac_priv *priv) +{ + struct plat_stmmacenet_data *plat_dat = priv->plat; + phy_interface_t interface; + int phy_intf_sel, ret; + + if (!plat_dat->set_phy_intf_sel) + return 0; + + interface = plat_dat->phy_interface; + phy_intf_sel = stmmac_get_phy_intf_sel(interface); + if (phy_intf_sel < 0) { + netdev_err(priv->dev, + "failed to get phy_intf_sel for %s: %pe\n", + phy_modes(interface), ERR_PTR(phy_intf_sel)); + return phy_intf_sel; + } + + ret = plat_dat->set_phy_intf_sel(plat_dat->bsp_priv, phy_intf_sel); + if (ret == -EINVAL) + netdev_err(priv->dev, "platform does not support %s\n", + phy_modes(interface)); + else if (ret < 0) + netdev_err(priv->dev, + "platform failed to set interface %s: %pe\n", + phy_modes(interface), ERR_PTR(ret)); + + return ret; +} + /** * stmmac_init_dma_engine - DMA init. * @priv: driver private structure @@ -3115,7 +3201,11 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv) if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE)) priv->plat->dma_cfg->atds = 1; - ret = stmmac_reset(priv, priv->ioaddr); + ret = stmmac_prereset_configure(priv); + if (ret) + return ret; + + ret = stmmac_reset(priv); if (ret) { netdev_err(priv->dev, "Failed to reset the dma\n"); return ret; @@ -3460,7 +3550,6 @@ static void stmmac_safety_feat_configuration(struct stmmac_priv *priv) /** * stmmac_hw_setup - setup mac in a usable state. * @dev : pointer to the device structure. - * @ptp_register: register PTP if set * Description: * this is the main function to setup the HW in a usable state because the * dma engine is reset, the core registers are configured (e.g. AXI, @@ -3470,7 +3559,7 @@ static void stmmac_safety_feat_configuration(struct stmmac_priv *priv) * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure. */ -static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) +static int stmmac_hw_setup(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); u32 rx_cnt = priv->plat->rx_queues_to_use; @@ -3504,19 +3593,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) stmmac_set_umac_addr(priv, priv->hw, dev->dev_addr, 0); phylink_rx_clk_stop_unblock(priv->phylink); - /* PS and related bits will be programmed according to the speed */ - if (priv->hw->pcs) { - int speed = priv->plat->mac_port_sel_speed; - - if ((speed == SPEED_10) || (speed == SPEED_100) || - (speed == SPEED_1000)) { - priv->hw->ps = speed; - } else { - dev_warn(priv->device, "invalid port speed\n"); - priv->hw->ps = 0; - } - } - /* Initialize the MAC Core */ stmmac_core_init(priv, priv->hw, dev); @@ -3541,22 +3617,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) stmmac_mmc_setup(priv); - if (ptp_register) { - ret = clk_prepare_enable(priv->plat->clk_ptp_ref); - if (ret < 0) - netdev_warn(priv->dev, - "failed to enable PTP reference clock: %pe\n", - ERR_PTR(ret)); - } - - ret = stmmac_init_ptp(priv); - if (ret == -EOPNOTSUPP) - netdev_info(priv->dev, "PTP not supported by HW\n"); - else if (ret) - netdev_warn(priv->dev, "PTP init failed\n"); - else if (ptp_register) - stmmac_ptp_register(priv); - if (priv->use_riwt) { u32 queue; @@ -3569,9 +3629,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) } } - if (priv->hw->pcs) - stmmac_pcs_ctrl_ane(priv, priv->ioaddr, 1, priv->hw->ps, 0); - /* set TX and RX rings length */ stmmac_set_rings_length(priv); @@ -3589,7 +3646,7 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) } /* Enable Split Header */ - sph_en = (priv->hw->rx_csum > 0) && priv->sph; + sph_en = (priv->hw->rx_csum > 0) && priv->sph_active; for (chan = 0; chan < rx_cnt; chan++) stmmac_enable_sph(priv, priv->ioaddr, sph_en, chan); @@ -3620,13 +3677,6 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register) return 0; } -static void stmmac_hw_teardown(struct net_device *dev) -{ - struct stmmac_priv *priv = netdev_priv(dev); - - clk_disable_unprepare(priv->plat->clk_ptp_ref); -} - static void stmmac_free_irq(struct net_device *dev, enum request_irq_err irq_err, int irq_idx) { @@ -3708,7 +3758,6 @@ static int stmmac_request_irq_multi_msi(struct net_device *dev) /* Request the Wake IRQ in case of another line * is used for WoL */ - priv->wol_irq_disabled = true; if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) { int_name = priv->int_name_wol; sprintf(int_name, "%s:%s", dev->name, "wol"); @@ -3869,7 +3918,6 @@ static int stmmac_request_irq_single(struct net_device *dev) /* Request the Wake IRQ in case of another line * is used for WoL */ - priv->wol_irq_disabled = true; if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) { ret = request_irq(priv->wol_irq, stmmac_interrupt, IRQF_SHARED, dev->name, dev); @@ -3953,12 +4001,13 @@ stmmac_setup_dma_desc(struct stmmac_priv *priv, unsigned int mtu) return ERR_PTR(-ENOMEM); } + /* Returns 0 or BUF_SIZE_16KiB if mtu > 8KiB and dwmac4 or ring mode */ bfsize = stmmac_set_16kib_bfsize(priv, mtu); if (bfsize < 0) bfsize = 0; if (bfsize < BUF_SIZE_16KiB) - bfsize = stmmac_set_bfsize(mtu, 0); + bfsize = stmmac_set_bfsize(mtu); dma_conf->dma_buf_sz = bfsize; /* Chose the tx/rx size from the already defined one in the @@ -4018,29 +4067,9 @@ static int __stmmac_open(struct net_device *dev, struct stmmac_dma_conf *dma_conf) { struct stmmac_priv *priv = netdev_priv(dev); - int mode = priv->plat->phy_interface; u32 chan; int ret; - /* Initialise the tx lpi timer, converting from msec to usec */ - if (!priv->tx_lpi_timer) - priv->tx_lpi_timer = eee_timer * 1000; - - ret = pm_runtime_resume_and_get(priv->device); - if (ret < 0) - return ret; - - if ((!priv->hw->xpcs || - xpcs_get_an_mode(priv->hw->xpcs, mode) != DW_AN_C73)) { - ret = stmmac_init_phy(dev); - if (ret) { - netdev_err(priv->dev, - "%s: Cannot attach to PHY (error: %d)\n", - __func__, ret); - goto init_phy_error; - } - } - for (int i = 0; i < MTL_MAX_TX_QUEUES; i++) if (priv->dma_conf.tx_queue[i].tbs & STMMAC_TBS_EN) dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs; @@ -4058,17 +4087,17 @@ static int __stmmac_open(struct net_device *dev, } } - ret = stmmac_hw_setup(dev, true); + ret = stmmac_hw_setup(dev); if (ret < 0) { netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); goto init_error; } + stmmac_setup_ptp(priv); + stmmac_init_coalesce(priv); phylink_start(priv->phylink); - /* We may have called phylink_speed_down before */ - phylink_speed_up(priv->phylink); ret = stmmac_request_irq(dev); if (ret) @@ -4086,11 +4115,8 @@ irq_error: for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - stmmac_hw_teardown(dev); + stmmac_release_ptp(priv); init_error: - phylink_disconnect_phy(priv->phylink); -init_phy_error: - pm_runtime_put(priv->device); return ret; } @@ -4100,34 +4126,50 @@ static int stmmac_open(struct net_device *dev) struct stmmac_dma_conf *dma_conf; int ret; + /* Initialise the tx lpi timer, converting from msec to usec */ + if (!priv->tx_lpi_timer) + priv->tx_lpi_timer = eee_timer * 1000; + dma_conf = stmmac_setup_dma_desc(priv, dev->mtu); if (IS_ERR(dma_conf)) return PTR_ERR(dma_conf); + ret = pm_runtime_resume_and_get(priv->device); + if (ret < 0) + goto err_dma_resources; + + ret = stmmac_init_phy(dev); + if (ret) + goto err_runtime_pm; + ret = __stmmac_open(dev, dma_conf); if (ret) - free_dma_desc_resources(priv, dma_conf); + goto err_disconnect_phy; + + kfree(dma_conf); + + /* We may have called phylink_speed_down before */ + phylink_speed_up(priv->phylink); + + return ret; +err_disconnect_phy: + phylink_disconnect_phy(priv->phylink); +err_runtime_pm: + pm_runtime_put(priv->device); +err_dma_resources: + free_dma_desc_resources(priv, dma_conf); kfree(dma_conf); return ret; } -/** - * stmmac_release - close entry point of the driver - * @dev : device pointer. - * Description: - * This is the stop entry point of the driver. - */ -static int stmmac_release(struct net_device *dev) +static void __stmmac_release(struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); u32 chan; - if (device_may_wakeup(priv->device)) - phylink_speed_down(priv->phylink, false); /* Stop and disconnect the PHY */ phylink_stop(priv->phylink); - phylink_disconnect_phy(priv->phylink); stmmac_disable_all_queues(priv); @@ -4152,8 +4194,29 @@ static int stmmac_release(struct net_device *dev) stmmac_release_ptp(priv); if (stmmac_fpe_supported(priv)) - timer_shutdown_sync(&priv->fpe_cfg.verify_timer); + ethtool_mmsv_stop(&priv->fpe_cfg.mmsv); +} + +/** + * stmmac_release - close entry point of the driver + * @dev : device pointer. + * Description: + * This is the stop entry point of the driver. + */ +static int stmmac_release(struct net_device *dev) +{ + struct stmmac_priv *priv = netdev_priv(dev); + /* If the PHY or MAC has WoL enabled, then the PHY will not be + * suspended when phylink_stop() is called below. Set the PHY + * to its slowest speed to save power. + */ + if (device_may_wakeup(priv->device)) + phylink_speed_down(priv->phylink, false); + + __stmmac_release(dev); + + phylink_disconnect_phy(priv->phylink); pm_runtime_put(priv->device); return 0; @@ -4162,18 +4225,11 @@ static int stmmac_release(struct net_device *dev) static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb, struct stmmac_tx_queue *tx_q) { - u16 tag = 0x0, inner_tag = 0x0; - u32 inner_type = 0x0; struct dma_desc *p; + u16 tag = 0x0; - if (!priv->dma_cap.vlins) - return false; - if (!skb_vlan_tag_present(skb)) + if (!priv->dma_cap.vlins || !skb_vlan_tag_present(skb)) return false; - if (skb->vlan_proto == htons(ETH_P_8021AD)) { - inner_tag = skb_vlan_tag_get(skb); - inner_type = STMMAC_VLAN_INSERT; - } tag = skb_vlan_tag_get(skb); @@ -4182,7 +4238,7 @@ static bool stmmac_vlan_insert(struct stmmac_priv *priv, struct sk_buff *skb, else p = &tx_q->dma_tx[tx_q->cur_tx]; - if (stmmac_set_desc_vlan_tag(priv, p, tag, inner_tag, inner_type)) + if (stmmac_set_desc_vlan_tag(priv, p, tag, 0x0, 0x0)) return false; stmmac_set_tx_owner(priv, p); @@ -4488,8 +4544,6 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) if (priv->sarc_type) stmmac_set_desc_sarc(priv, first, priv->sarc_type); - skb_tx_timestamp(skb); - if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) && priv->hwts_tx_en)) { /* declare that device is doing timestamping */ @@ -4522,6 +4576,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) } netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len); + skb_tx_timestamp(skb); stmmac_flush_tx_descriptors(priv, queue); stmmac_tx_timer_arm(priv, queue); @@ -4567,20 +4622,21 @@ static bool stmmac_has_ip_ethertype(struct sk_buff *skb) */ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) { - unsigned int first_entry, tx_packets, enh_desc; + bool enh_desc, has_vlan, set_ic, is_jumbo = false; struct stmmac_priv *priv = netdev_priv(dev); unsigned int nopaged_len = skb_headlen(skb); - int i, csum_insertion = 0, is_jumbo = 0; u32 queue = skb_get_queue_mapping(skb); int nfrags = skb_shinfo(skb)->nr_frags; + unsigned int first_entry, tx_packets; int gso = skb_shinfo(skb)->gso_type; struct stmmac_txq_stats *txq_stats; struct dma_edesc *tbs_desc = NULL; struct dma_desc *desc, *first; struct stmmac_tx_queue *tx_q; - bool has_vlan, set_ic; + int i, csum_insertion = 0; int entry, first_tx; dma_addr_t des; + u32 sdu_len; tx_q = &priv->dma_conf.tx_queue[queue]; txq_stats = &priv->xstats.txq_stats[queue]; @@ -4593,15 +4649,21 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (skb_is_gso(skb) && priv->tso) { if (gso & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) return stmmac_tso_xmit(skb, dev); - if (priv->plat->has_gmac4 && (gso & SKB_GSO_UDP_L4)) + if (priv->plat->core_type == DWMAC_CORE_GMAC4 && + (gso & SKB_GSO_UDP_L4)) return stmmac_tso_xmit(skb, dev); } if (priv->est && priv->est->enable && - priv->est->max_sdu[queue] && - skb->len > priv->est->max_sdu[queue]){ - priv->xstats.max_sdu_txq_drop[queue]++; - goto max_sdu_err; + priv->est->max_sdu[queue]) { + sdu_len = skb->len; + /* Add VLAN tag length if VLAN tag insertion offload is requested */ + if (priv->dma_cap.vlins && skb_vlan_tag_present(skb)) + sdu_len += VLAN_HLEN; + if (sdu_len > priv->est->max_sdu[queue]) { + priv->xstats.max_sdu_txq_drop[queue]++; + goto max_sdu_err; + } } if (unlikely(stmmac_tx_avail(priv, queue) < nfrags + 1)) { @@ -4765,8 +4827,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) if (priv->sarc_type) stmmac_set_desc_sarc(priv, first, priv->sarc_type); - skb_tx_timestamp(skb); - /* Ready to fill the first descriptor and set the OWN bit w/o any * problems because all the descriptors are actually ready to be * passed to the DMA engine. @@ -4813,7 +4873,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) netdev_tx_sent_queue(netdev_get_tx_queue(dev, queue), skb->len); stmmac_enable_dma_transmission(priv, priv->ioaddr, queue); - + skb_tx_timestamp(skb); stmmac_flush_tx_descriptors(priv, queue); stmmac_tx_timer_arm(priv, queue); @@ -4878,7 +4938,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) break; } - if (priv->sph && !buf->sec_page) { + if (priv->sph_active && !buf->sec_page) { buf->sec_page = page_pool_alloc_pages(rx_q->page_pool, gfp); if (!buf->sec_page) break; @@ -4889,7 +4949,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) buf->addr = page_pool_get_dma_addr(buf->page) + buf->page_offset; stmmac_set_desc_addr(priv, p, buf->addr); - if (priv->sph) + if (priv->sph_active) stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, true); else stmmac_set_desc_sec_addr(priv, p, buf->sec_addr, false); @@ -4914,6 +4974,8 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue) rx_q->rx_tail_addr = rx_q->dma_rx_phy + (rx_q->dirty_rx * sizeof(struct dma_desc)); stmmac_set_rx_tail_ptr(priv, priv->ioaddr, rx_q->rx_tail_addr, queue); + /* Wake up Rx DMA from the suspend state if required */ + stmmac_enable_dma_reception(priv, priv->ioaddr, queue); } static unsigned int stmmac_rx_buf1_len(struct stmmac_priv *priv, @@ -4924,12 +4986,12 @@ static unsigned int stmmac_rx_buf1_len(struct stmmac_priv *priv, int coe = priv->hw->rx_csum; /* Not first descriptor, buffer is always zero */ - if (priv->sph && len) + if (priv->sph_active && len) return 0; /* First descriptor, get split header length */ stmmac_get_rx_header_len(priv, p, &hlen); - if (priv->sph && hlen) { + if (priv->sph_active && hlen) { priv->xstats.rx_split_hdr_pkt_n++; return hlen; } @@ -4952,7 +5014,7 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, unsigned int plen = 0; /* Not split header, buffer is not available */ - if (!priv->sph) + if (!priv->sph_active) return 0; /* Not last descriptor */ @@ -4970,6 +5032,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, { struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + bool csum = !priv->plat->tx_queues_cfg[queue].coe_unsupported; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc; dma_addr_t dma_addr; @@ -5021,7 +5084,7 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, stmmac_set_desc_addr(priv, tx_desc, dma_addr); stmmac_prepare_tx_desc(priv, tx_desc, 1, xdpf->len, - true, priv->mode, true, true, + csum, priv->mode, true, true, xdpf->len); tx_q->tx_count_frames++; @@ -5064,6 +5127,7 @@ static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv, static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, struct xdp_buff *xdp) { + bool zc = !!(xdp->rxq->mem.type == MEM_TYPE_XSK_BUFF_POOL); struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); int cpu = smp_processor_id(); struct netdev_queue *nq; @@ -5080,9 +5144,18 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, /* Avoids TX time-out as we are sharing with slow path */ txq_trans_cond_update(nq); - res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false); - if (res == STMMAC_XDP_TX) + /* For zero copy XDP_TX action, dma_map is true */ + res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc); + if (res == STMMAC_XDP_TX) { stmmac_flush_tx_descriptors(priv, queue); + } else if (res == STMMAC_XDP_CONSUMED && zc) { + /* xdp has been freed by xdp_convert_buff_to_frame(), + * no need to call xsk_buff_free() again, so return + * STMMAC_XSK_CONSUMED. + */ + res = STMMAC_XSK_CONSUMED; + xdp_return_frame(xdpf); + } __netif_tx_unlock(nq); @@ -5334,10 +5407,10 @@ static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) len = 0; } +read_again: if (count >= limit) break; -read_again: buf1_len = 0; entry = next_entry; buf = &rx_q->buf_pool[entry]; @@ -5432,6 +5505,8 @@ read_again: break; case STMMAC_XDP_CONSUMED: xsk_buff_free(buf->xdp); + fallthrough; + case STMMAC_XSK_CONSUMED: rx_dropped++; break; case STMMAC_XDP_TX: @@ -5720,7 +5795,8 @@ drain_data: skb->protocol = eth_type_trans(skb, priv->dev); - if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb)) + if (unlikely(!coe) || !stmmac_has_ip_ethertype(skb) || + (status & csum_none)) skb_checksum_none_assert(skb); else skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -5952,7 +6028,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return PTR_ERR(dma_conf); } - stmmac_release(dev); + __stmmac_release(dev); ret = __stmmac_open(dev, dma_conf); if (ret) { @@ -6018,8 +6094,8 @@ static int stmmac_set_features(struct net_device *netdev, */ stmmac_rx_ipc(priv, priv->hw); - if (priv->sph_cap) { - bool sph_en = (priv->hw->rx_csum > 0) && priv->sph; + if (priv->sph_capable) { + bool sph_en = (priv->hw->rx_csum > 0) && priv->sph_active; u32 chan; for (chan = 0; chan < priv->plat->rx_queues_to_use; chan++) @@ -6046,7 +6122,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) u32 queue; bool xmac; - xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; + xmac = dwmac_is_xmac(priv->plat->core_type); queues_count = (rx_cnt > tx_cnt) ? rx_cnt : tx_cnt; if (priv->irq_wake) @@ -6060,7 +6136,7 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) stmmac_fpe_irq_status(priv); /* To handle GMAC own interrupts */ - if ((priv->plat->has_gmac) || xmac) { + if (priv->plat->core_type == DWMAC_CORE_GMAC || xmac) { int status = stmmac_host_irq_status(priv, priv->hw, &priv->xstats); if (unlikely(status)) { @@ -6074,15 +6150,6 @@ static void stmmac_common_interrupt(struct stmmac_priv *priv) for (queue = 0; queue < queues_count; queue++) stmmac_host_mtl_irq_status(priv, priv->hw, queue); - /* PCS link status */ - if (priv->hw->pcs && - !(priv->plat->flags & STMMAC_FLAG_HAS_INTEGRATED_PCS)) { - if (priv->xstats.pcs_link) - netif_carrier_on(priv->dev); - else - netif_carrier_off(priv->dev); - } - stmmac_timestamp_interrupt(priv, priv); } } @@ -6219,12 +6286,6 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) case SIOCSMIIREG: ret = phylink_mii_ioctl(priv->phylink, rq, cmd); break; - case SIOCSHWTSTAMP: - ret = stmmac_hwtstamp_set(dev, rq); - break; - case SIOCGHWTSTAMP: - ret = stmmac_hwtstamp_get(dev, rq); - break; default: break; } @@ -6436,7 +6497,7 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v) (priv->dma_cap.mbps_1000) ? "Y" : "N"); seq_printf(seq, "\tHalf duplex: %s\n", (priv->dma_cap.half_duplex) ? "Y" : "N"); - if (priv->plat->has_xgmac) { + if (priv->plat->core_type == DWMAC_CORE_XGMAC) { seq_printf(seq, "\tNumber of Additional MAC address registers: %d\n", priv->dma_cap.multi_addr); @@ -6460,7 +6521,7 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v) (priv->dma_cap.time_stamp) ? "Y" : "N"); seq_printf(seq, "\tIEEE 1588-2008 Advanced Time Stamp: %s\n", (priv->dma_cap.atime_stamp) ? "Y" : "N"); - if (priv->plat->has_xgmac) + if (priv->plat->core_type == DWMAC_CORE_XGMAC) seq_printf(seq, "\tTimestamp System Time Source: %s\n", dwxgmac_timestamp_source[priv->dma_cap.tssrc]); seq_printf(seq, "\t802.3az - Energy-Efficient Ethernet (EEE): %s\n", @@ -6469,7 +6530,7 @@ static int stmmac_dma_cap_show(struct seq_file *seq, void *v) seq_printf(seq, "\tChecksum Offload in TX: %s\n", (priv->dma_cap.tx_coe) ? "Y" : "N"); if (priv->synopsys_id >= DWMAC_CORE_4_00 || - priv->plat->has_xgmac) { + priv->plat->core_type == DWMAC_CORE_XGMAC) { seq_printf(seq, "\tIP Checksum Offload in RX: %s\n", (priv->dma_cap.rx_coe) ? "Y" : "N"); } else { @@ -6983,7 +7044,7 @@ int stmmac_xdp_open(struct net_device *dev) } /* Adjust Split header */ - sph_en = (priv->hw->rx_csum > 0) && priv->sph; + sph_en = (priv->hw->rx_csum > 0) && priv->sph_active; /* DMA RX Channel Configuration */ for (chan = 0; chan < rx_cnt; chan++) { @@ -7048,7 +7109,6 @@ irq_error: for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer); - stmmac_hw_teardown(dev); init_error: free_dma_desc_resources(priv, &priv->dma_conf); dma_desc_error: @@ -7163,6 +7223,8 @@ static const struct net_device_ops stmmac_netdev_ops = { .ndo_bpf = stmmac_bpf, .ndo_xdp_xmit = stmmac_xdp_xmit, .ndo_xsk_wakeup = stmmac_xsk_wakeup, + .ndo_hwtstamp_get = stmmac_hwtstamp_get, + .ndo_hwtstamp_set = stmmac_hwtstamp_set, }; static void stmmac_reset_subtask(struct stmmac_priv *priv) @@ -7231,7 +7293,6 @@ static int stmmac_hw_init(struct stmmac_priv *priv) priv->plat->enh_desc = priv->dma_cap.enh_desc; priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up && !(priv->plat->flags & STMMAC_FLAG_USE_PHY_WOL); - priv->hw->pmt = priv->plat->pmt; if (priv->dma_cap.hash_tb_sz) { priv->hw->multicast_filter_bins = (BIT(priv->dma_cap.hash_tb_sz) << 5); @@ -7269,6 +7330,7 @@ static int stmmac_hw_init(struct stmmac_priv *priv) if (priv->plat->pmt) { dev_info(priv->device, "Wake-Up On Lan supported\n"); device_set_wakeup_capable(priv->device, 1); + devm_pm_set_wake_irq(priv->device, priv->wol_irq); } if (priv->dma_cap.tsoen) @@ -7320,13 +7382,21 @@ static int stmmac_hw_init(struct stmmac_priv *priv) * has to be disable and this can be done by passing the * riwt_off field from the platform. */ - if (((priv->synopsys_id >= DWMAC_CORE_3_50) || - (priv->plat->has_xgmac)) && (!priv->plat->riwt_off)) { + if ((priv->synopsys_id >= DWMAC_CORE_3_50 || + priv->plat->core_type == DWMAC_CORE_XGMAC) && + !priv->plat->riwt_off) { priv->use_riwt = 1; dev_info(priv->device, "Enable RX Mitigation via HW Watchdog Timer\n"); } + /* Unimplemented PCS init (as indicated by stmmac_do_callback() + * perversely returning -EINVAL) is non-fatal. + */ + ret = stmmac_mac_pcs_init(priv); + if (ret != -EINVAL) + return ret; + return 0; } @@ -7435,7 +7505,7 @@ static int stmmac_xdp_rx_timestamp(const struct xdp_md *_ctx, u64 *timestamp) return -ENODATA; /* For GMAC4, the valid timestamp is from CTX next desc. */ - if (priv->plat->has_gmac4 || priv->plat->has_xgmac) + if (dwmac_is_xmac(priv->plat->core_type)) desc_contains_ts = ndesc; /* Check if timestamp is available */ @@ -7453,19 +7523,133 @@ static const struct xdp_metadata_ops stmmac_xdp_metadata_ops = { .xmo_rx_timestamp = stmmac_xdp_rx_timestamp, }; -/** - * stmmac_dvr_probe - * @device: device pointer - * @plat_dat: platform data pointer - * @res: stmmac resource pointer - * Description: this is the main probe function used to - * call the alloc_etherdev, allocate the priv structure. - * Return: - * returns 0 on success, otherwise errno. - */ -int stmmac_dvr_probe(struct device *device, - struct plat_stmmacenet_data *plat_dat, - struct stmmac_resources *res) +static int stmmac_dl_ts_coarse_set(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx, + struct netlink_ext_ack *extack) +{ + struct stmmac_devlink_priv *dl_priv = devlink_priv(dl); + struct stmmac_priv *priv = dl_priv->stmmac_priv; + + priv->tsfupdt_coarse = ctx->val.vbool; + + if (priv->tsfupdt_coarse) + priv->systime_flags &= ~PTP_TCR_TSCFUPDT; + else + priv->systime_flags |= PTP_TCR_TSCFUPDT; + + /* In Coarse mode, we can use a smaller subsecond increment, let's + * reconfigure the systime, subsecond increment and addend. + */ + stmmac_update_subsecond_increment(priv); + + return 0; +} + +static int stmmac_dl_ts_coarse_get(struct devlink *dl, u32 id, + struct devlink_param_gset_ctx *ctx, + struct netlink_ext_ack *extack) +{ + struct stmmac_devlink_priv *dl_priv = devlink_priv(dl); + struct stmmac_priv *priv = dl_priv->stmmac_priv; + + ctx->val.vbool = priv->tsfupdt_coarse; + + return 0; +} + +static const struct devlink_param stmmac_devlink_params[] = { + DEVLINK_PARAM_DRIVER(STMMAC_DEVLINK_PARAM_ID_TS_COARSE, "phc_coarse_adj", + DEVLINK_PARAM_TYPE_BOOL, + BIT(DEVLINK_PARAM_CMODE_RUNTIME), + stmmac_dl_ts_coarse_get, + stmmac_dl_ts_coarse_set, NULL), +}; + +/* None of the generic devlink parameters are implemented */ +static const struct devlink_ops stmmac_devlink_ops = {}; + +static int stmmac_register_devlink(struct stmmac_priv *priv) +{ + struct stmmac_devlink_priv *dl_priv; + int ret; + + /* For now, what is exposed over devlink is only relevant when + * timestamping is available and we have a valid ptp clock rate + */ + if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp) || + !priv->plat->clk_ptp_rate) + return 0; + + priv->devlink = devlink_alloc(&stmmac_devlink_ops, sizeof(*dl_priv), + priv->device); + if (!priv->devlink) + return -ENOMEM; + + dl_priv = devlink_priv(priv->devlink); + dl_priv->stmmac_priv = priv; + + ret = devlink_params_register(priv->devlink, stmmac_devlink_params, + ARRAY_SIZE(stmmac_devlink_params)); + if (ret) + goto dl_free; + + devlink_register(priv->devlink); + return 0; + +dl_free: + devlink_free(priv->devlink); + + return ret; +} + +static void stmmac_unregister_devlink(struct stmmac_priv *priv) +{ + if (!priv->devlink) + return; + + devlink_unregister(priv->devlink); + devlink_params_unregister(priv->devlink, stmmac_devlink_params, + ARRAY_SIZE(stmmac_devlink_params)); + devlink_free(priv->devlink); +} + +struct plat_stmmacenet_data *stmmac_plat_dat_alloc(struct device *dev) +{ + struct plat_stmmacenet_data *plat_dat; + int i; + + plat_dat = devm_kzalloc(dev, sizeof(*plat_dat), GFP_KERNEL); + if (!plat_dat) + return NULL; + + /* Set the defaults: + * - phy autodetection + * - determine GMII_Address CR field from CSR clock + * - allow MTU up to JUMBO_LEN + * - hash table size + * - one unicast filter entry + */ + plat_dat->phy_addr = -1; + plat_dat->clk_csr = -1; + plat_dat->maxmtu = JUMBO_LEN; + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + plat_dat->unicast_filter_entries = 1; + + /* Set the mtl defaults */ + plat_dat->tx_queues_to_use = 1; + plat_dat->rx_queues_to_use = 1; + + /* Setup the default RX queue channel map */ + for (i = 0; i < ARRAY_SIZE(plat_dat->rx_queues_cfg); i++) + plat_dat->rx_queues_cfg[i].chan = i; + + return plat_dat; +} +EXPORT_SYMBOL_GPL(stmmac_plat_dat_alloc); + +static int __stmmac_dvr_probe(struct device *device, + struct plat_stmmacenet_data *plat_dat, + struct stmmac_resources *res) { struct net_device *ndev = NULL; struct stmmac_priv *priv; @@ -7591,7 +7775,7 @@ int stmmac_dvr_probe(struct device *device, if ((priv->plat->flags & STMMAC_FLAG_TSO_EN) && (priv->dma_cap.tsoen)) { ndev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; - if (priv->plat->has_gmac4) + if (priv->plat->core_type == DWMAC_CORE_GMAC4) ndev->hw_features |= NETIF_F_GSO_UDP_L4; priv->tso = true; dev_info(priv->device, "TSO feature enabled\n"); @@ -7600,8 +7784,8 @@ int stmmac_dvr_probe(struct device *device, if (priv->dma_cap.sphen && !(priv->plat->flags & STMMAC_FLAG_SPH_DISABLE)) { ndev->hw_features |= NETIF_F_GRO; - priv->sph_cap = true; - priv->sph = priv->sph_cap; + priv->sph_capable = true; + priv->sph_active = priv->sph_capable; dev_info(priv->device, "SPH feature enabled\n"); } @@ -7644,7 +7828,7 @@ int stmmac_dvr_probe(struct device *device, #ifdef STMMAC_VLAN_TAG_USED /* Both mac100 and gmac support receive VLAN tag detection */ ndev->features |= NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_STAG_RX; - if (priv->plat->has_gmac4) { + if (dwmac_is_xmac(priv->plat->core_type)) { ndev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; priv->hw->hw_vlan_en = true; } @@ -7652,11 +7836,8 @@ int stmmac_dvr_probe(struct device *device, ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; ndev->features |= NETIF_F_HW_VLAN_STAG_FILTER; } - if (priv->dma_cap.vlins) { + if (priv->dma_cap.vlins) ndev->features |= NETIF_F_HW_VLAN_CTAG_TX; - if (priv->dma_cap.dvlan) - ndev->features |= NETIF_F_HW_VLAN_STAG_TX; - } #endif priv->msg_enable = netif_msg_init(debug, default_msg_level); @@ -7675,22 +7856,23 @@ int stmmac_dvr_probe(struct device *device, /* MTU range: 46 - hw-specific max */ ndev->min_mtu = ETH_ZLEN - ETH_HLEN; - if (priv->plat->has_xgmac) + + if (priv->plat->core_type == DWMAC_CORE_XGMAC) ndev->max_mtu = XGMAC_JUMBO_LEN; - else if ((priv->plat->enh_desc) || (priv->synopsys_id >= DWMAC_CORE_4_00)) + else if (priv->plat->enh_desc || priv->synopsys_id >= DWMAC_CORE_4_00) ndev->max_mtu = JUMBO_LEN; else ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); - /* Will not overwrite ndev->max_mtu if plat->maxmtu > ndev->max_mtu - * as well as plat->maxmtu < ndev->min_mtu which is a invalid range. + + /* Warn if the platform's maxmtu is smaller than the minimum MTU, + * otherwise clamp the maximum MTU above to the platform's maxmtu. */ - if ((priv->plat->maxmtu < ndev->max_mtu) && - (priv->plat->maxmtu >= ndev->min_mtu)) - ndev->max_mtu = priv->plat->maxmtu; - else if (priv->plat->maxmtu < ndev->min_mtu) + if (priv->plat->maxmtu < ndev->min_mtu) dev_warn(priv->device, "%s: warning: maxmtu having invalid value (%d)\n", __func__, priv->plat->maxmtu); + else if (priv->plat->maxmtu < ndev->max_mtu) + ndev->max_mtu = priv->plat->maxmtu; ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; @@ -7701,17 +7883,6 @@ int stmmac_dvr_probe(struct device *device, stmmac_fpe_init(priv); - /* If a specific clk_csr value is passed from the platform - * this means that the CSR Clock Range selection cannot be - * changed at run-time and it is fixed. Viceversa the driver'll try to - * set the MDC clock dynamically according to the csr actual - * clock input. - */ - if (priv->plat->clk_csr >= 0) - priv->clk_csr = priv->plat->clk_csr; - else - stmmac_clk_csr_set(priv); - stmmac_check_pcs_mode(priv); pm_runtime_get_noresume(device); @@ -7727,19 +7898,20 @@ int stmmac_dvr_probe(struct device *device, goto error_mdio_register; } - if (priv->plat->speed_mode_2500) - priv->plat->speed_mode_2500(ndev, priv->plat->bsp_priv); - ret = stmmac_pcs_setup(ndev); if (ret) goto error_pcs_setup; - ret = stmmac_phy_setup(priv); + ret = stmmac_phylink_setup(priv); if (ret) { netdev_err(ndev, "failed to setup phy (%d)\n", ret); goto error_phy_setup; } + ret = stmmac_register_devlink(priv); + if (ret) + goto error_devlink_setup; + ret = register_netdev(ndev); if (ret) { dev_err(priv->device, "%s: ERROR %i registering the device\n", @@ -7762,6 +7934,8 @@ int stmmac_dvr_probe(struct device *device, return ret; error_netdev_register: + stmmac_unregister_devlink(priv); +error_devlink_setup: phylink_destroy(priv->phylink); error_phy_setup: stmmac_pcs_clean(ndev); @@ -7776,6 +7950,34 @@ error_wq_init: return ret; } + +/** + * stmmac_dvr_probe + * @dev: device pointer + * @plat_dat: platform data pointer + * @res: stmmac resource pointer + * Description: this is the main probe function used to + * call the alloc_etherdev, allocate the priv structure. + * Return: + * returns 0 on success, otherwise errno. + */ +int stmmac_dvr_probe(struct device *dev, struct plat_stmmacenet_data *plat_dat, + struct stmmac_resources *res) +{ + int ret; + + if (plat_dat->init) { + ret = plat_dat->init(dev, plat_dat->bsp_priv); + if (ret) + return ret; + } + + ret = __stmmac_dvr_probe(dev, plat_dat, res); + if (ret && plat_dat->exit) + plat_dat->exit(dev, plat_dat->bsp_priv); + + return ret; +} EXPORT_SYMBOL_GPL(stmmac_dvr_probe); /** @@ -7798,6 +8000,8 @@ void stmmac_dvr_remove(struct device *dev) #ifdef CONFIG_DEBUG_FS stmmac_exit_fs(ndev); #endif + stmmac_unregister_devlink(priv); + phylink_destroy(priv->phylink); if (priv->plat->stmmac_rst) reset_control_assert(priv->plat->stmmac_rst); @@ -7812,6 +8016,9 @@ void stmmac_dvr_remove(struct device *dev) pm_runtime_disable(dev); pm_runtime_put_noidle(dev); + + if (priv->plat->exit) + priv->plat->exit(dev, priv->plat->bsp_priv); } EXPORT_SYMBOL_GPL(stmmac_dvr_remove); @@ -7852,7 +8059,7 @@ int stmmac_suspend(struct device *dev) priv->plat->serdes_powerdown(ndev, priv->plat->bsp_priv); /* Enable Power down mode by programming the PMT regs */ - if (device_may_wakeup(priv->device) && priv->plat->pmt) { + if (priv->wolopts) { stmmac_pmt(priv, priv->hw, priv->wolopts); priv->irq_wake = 1; } else { @@ -7863,15 +8070,14 @@ int stmmac_suspend(struct device *dev) mutex_unlock(&priv->lock); rtnl_lock(); - if (device_may_wakeup(priv->device) && !priv->plat->pmt) - phylink_speed_down(priv->phylink, false); - - phylink_suspend(priv->phylink, - device_may_wakeup(priv->device) && priv->plat->pmt); + phylink_suspend(priv->phylink, !!priv->wolopts); rtnl_unlock(); if (stmmac_fpe_supported(priv)) - timer_shutdown_sync(&priv->fpe_cfg.verify_timer); + ethtool_mmsv_stop(&priv->fpe_cfg.mmsv); + + if (priv->plat->suspend) + return priv->plat->suspend(dev, priv->plat->bsp_priv); return 0; } @@ -7925,6 +8131,12 @@ int stmmac_resume(struct device *dev) struct stmmac_priv *priv = netdev_priv(ndev); int ret; + if (priv->plat->resume) { + ret = priv->plat->resume(dev, priv->plat->bsp_priv); + if (ret) + return ret; + } + if (!netif_running(ndev)) return 0; @@ -7934,7 +8146,7 @@ int stmmac_resume(struct device *dev) * this bit because it can generate problems while resuming * from another devices (e.g. serial console). */ - if (device_may_wakeup(priv->device) && priv->plat->pmt) { + if (priv->wolopts) { mutex_lock(&priv->lock); stmmac_pmt(priv, priv->hw, 0); mutex_unlock(&priv->lock); @@ -7969,7 +8181,16 @@ int stmmac_resume(struct device *dev) stmmac_free_tx_skbufs(priv); stmmac_clear_descriptors(priv, &priv->dma_conf); - stmmac_hw_setup(ndev, false); + ret = stmmac_hw_setup(ndev); + if (ret < 0) { + netdev_err(priv->dev, "%s: Hw setup failed\n", __func__); + mutex_unlock(&priv->lock); + rtnl_unlock(); + return ret; + } + + stmmac_init_timestamping(priv); + stmmac_init_coalesce(priv); phylink_rx_clk_stop_block(priv->phylink); stmmac_set_rx_mode(ndev); @@ -7987,9 +8208,6 @@ int stmmac_resume(struct device *dev) * workqueue thread, which will race with initialisation. */ phylink_resume(priv->phylink); - if (device_may_wakeup(priv->device) && !priv->plat->pmt) - phylink_speed_up(priv->phylink); - rtnl_unlock(); netif_device_attach(ndev); @@ -7998,6 +8216,10 @@ int stmmac_resume(struct device *dev) } EXPORT_SYMBOL_GPL(stmmac_resume); +/* This is not the same as EXPORT_GPL_SIMPLE_DEV_PM_OPS() when CONFIG_PM=n */ +DEFINE_SIMPLE_DEV_PM_OPS(stmmac_simple_pm_ops, stmmac_suspend, stmmac_resume); +EXPORT_SYMBOL_GPL(stmmac_simple_pm_ops); + #ifndef MODULE static int __init stmmac_cmdline_opt(char *str) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 836f2848dfeb..1e82850f2a25 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -23,9 +23,9 @@ #include "dwxgmac2.h" #include "stmmac.h" -#define MII_BUSY 0x00000001 -#define MII_WRITE 0x00000002 -#define MII_DATA_MASK GENMASK(15, 0) +#define MII_ADDR_GBUSY BIT(0) +#define MII_ADDR_GWRITE BIT(1) +#define MII_DATA_GD_MASK GENMASK(15, 0) /* GMAC4 defines */ #define MII_GMAC4_GOC_SHIFT 2 @@ -45,6 +45,16 @@ #define MII_XGMAC_PA_SHIFT 16 #define MII_XGMAC_DA_SHIFT 21 +static int stmmac_mdio_wait(void __iomem *reg, u32 mask) +{ + u32 v; + + if (readl_poll_timeout(reg, v, !(v & mask), 100, 10000)) + return -EBUSY; + + return 0; +} + static void stmmac_xgmac2_c45_format(struct stmmac_priv *priv, int phyaddr, int devad, int phyreg, u32 *hw_addr) { @@ -83,7 +93,6 @@ static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr, { unsigned int mii_address = priv->hw->mii.addr; unsigned int mii_data = priv->hw->mii.data; - u32 tmp; int ret; ret = pm_runtime_resume_and_get(priv->device); @@ -91,33 +100,25 @@ static int stmmac_xgmac2_mdio_read(struct stmmac_priv *priv, u32 addr, return ret; /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000)) { - ret = -EBUSY; + ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY); + if (ret) goto err_disable_clks; - } - value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) - & priv->hw->mii.clk_csr_mask; - value |= MII_XGMAC_READ; + value |= priv->gmii_address_bus_config | MII_XGMAC_READ; /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000)) { - ret = -EBUSY; + ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY); + if (ret) goto err_disable_clks; - } /* Set the MII address register to read */ writel(addr, priv->ioaddr + mii_address); writel(value, priv->ioaddr + mii_data); /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000)) { - ret = -EBUSY; + ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY); + if (ret) goto err_disable_clks; - } /* Read the data from the MII data register */ ret = (int)readl(priv->ioaddr + mii_data) & GENMASK(15, 0); @@ -131,12 +132,9 @@ err_disable_clks: static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv; + struct stmmac_priv *priv = netdev_priv(bus->priv); u32 addr; - priv = netdev_priv(ndev); - /* Until ver 2.20 XGMAC does not support C22 addr >= 4 */ if (priv->synopsys_id < DWXGMAC_CORE_2_20 && phyaddr > MII_XGMAC_MAX_C22ADDR) @@ -150,12 +148,9 @@ static int stmmac_xgmac2_mdio_read_c22(struct mii_bus *bus, int phyaddr, static int stmmac_xgmac2_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad, int phyreg) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv; + struct stmmac_priv *priv = netdev_priv(bus->priv); u32 addr; - priv = netdev_priv(ndev); - stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr); return stmmac_xgmac2_mdio_read(priv, addr, MII_XGMAC_BUSY); @@ -166,7 +161,6 @@ static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr, { unsigned int mii_address = priv->hw->mii.addr; unsigned int mii_data = priv->hw->mii.data; - u32 tmp; int ret; ret = pm_runtime_resume_and_get(priv->device); @@ -174,31 +168,23 @@ static int stmmac_xgmac2_mdio_write(struct stmmac_priv *priv, u32 addr, return ret; /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000)) { - ret = -EBUSY; + ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY); + if (ret) goto err_disable_clks; - } - value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) - & priv->hw->mii.clk_csr_mask; - value |= phydata; - value |= MII_XGMAC_WRITE; + value |= priv->gmii_address_bus_config | phydata | MII_XGMAC_WRITE; /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000)) { - ret = -EBUSY; + ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY); + if (ret) goto err_disable_clks; - } /* Set the MII address register to write */ writel(addr, priv->ioaddr + mii_address); writel(value, priv->ioaddr + mii_data); /* Wait until any existing MII operation is complete */ - ret = readl_poll_timeout(priv->ioaddr + mii_data, tmp, - !(tmp & MII_XGMAC_BUSY), 100, 10000); + ret = stmmac_mdio_wait(priv->ioaddr + mii_data, MII_XGMAC_BUSY); err_disable_clks: pm_runtime_put(priv->device); @@ -209,12 +195,9 @@ err_disable_clks: static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg, u16 phydata) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv; + struct stmmac_priv *priv = netdev_priv(bus->priv); u32 addr; - priv = netdev_priv(ndev); - /* Until ver 2.20 XGMAC does not support C22 addr >= 4 */ if (priv->synopsys_id < DWXGMAC_CORE_2_20 && phyaddr > MII_XGMAC_MAX_C22ADDR) @@ -229,37 +212,78 @@ static int stmmac_xgmac2_mdio_write_c22(struct mii_bus *bus, int phyaddr, static int stmmac_xgmac2_mdio_write_c45(struct mii_bus *bus, int phyaddr, int devad, int phyreg, u16 phydata) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv; + struct stmmac_priv *priv = netdev_priv(bus->priv); u32 addr; - priv = netdev_priv(ndev); - stmmac_xgmac2_c45_format(priv, phyaddr, devad, phyreg, &addr); return stmmac_xgmac2_mdio_write(priv, addr, MII_XGMAC_BUSY, phydata); } -static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value) +/** + * stmmac_mdio_format_addr() - format the address register + * @priv: struct stmmac_priv pointer + * @pa: 5-bit MDIO package address + * @gr: 5-bit MDIO register address (C22) or MDIO device address (C45) + * + * Return: formatted address register + */ +static u32 stmmac_mdio_format_addr(struct stmmac_priv *priv, + unsigned int pa, unsigned int gr) { - unsigned int mii_address = priv->hw->mii.addr; - unsigned int mii_data = priv->hw->mii.data; - u32 v; + const struct mii_regs *mii_regs = &priv->hw->mii; - if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), - 100, 10000)) - return -EBUSY; + return ((pa << mii_regs->addr_shift) & mii_regs->addr_mask) | + ((gr << mii_regs->reg_shift) & mii_regs->reg_mask) | + priv->gmii_address_bus_config | + MII_ADDR_GBUSY; +} - writel(data, priv->ioaddr + mii_data); - writel(value, priv->ioaddr + mii_address); +static int stmmac_mdio_access(struct stmmac_priv *priv, unsigned int pa, + unsigned int gr, u32 cmd, u32 data, bool read) +{ + void __iomem *mii_address = priv->ioaddr + priv->hw->mii.addr; + void __iomem *mii_data = priv->ioaddr + priv->hw->mii.data; + u32 addr; + int ret; - if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), - 100, 10000)) - return -EBUSY; + ret = pm_runtime_resume_and_get(priv->device); + if (ret < 0) + return ret; - /* Read the data from the MII data register */ - return readl(priv->ioaddr + mii_data) & MII_DATA_MASK; + ret = stmmac_mdio_wait(mii_address, MII_ADDR_GBUSY); + if (ret) + goto out; + + addr = stmmac_mdio_format_addr(priv, pa, gr) | cmd; + + writel(data, mii_data); + writel(addr, mii_address); + + ret = stmmac_mdio_wait(mii_address, MII_ADDR_GBUSY); + if (ret) + goto out; + + /* Read the data from the MII data register if in read mode */ + ret = read ? readl(mii_data) & MII_DATA_GD_MASK : 0; + +out: + pm_runtime_put(priv->device); + + return ret; +} + +static int stmmac_mdio_read(struct stmmac_priv *priv, unsigned int pa, + unsigned int gr, u32 cmd, int data) +{ + return stmmac_mdio_access(priv, pa, gr, cmd, data, true); +} + +static int stmmac_mdio_write(struct stmmac_priv *priv, unsigned int pa, + unsigned int gr, u32 cmd, int data) +{ + return stmmac_mdio_access(priv, pa, gr, cmd, data, false); } /** @@ -274,28 +298,15 @@ static int stmmac_mdio_read(struct stmmac_priv *priv, int data, u32 value) */ static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv = netdev_priv(ndev); - u32 value = MII_BUSY; - int data = 0; - - data = pm_runtime_resume_and_get(priv->device); - if (data < 0) - return data; + struct stmmac_priv *priv = netdev_priv(bus->priv); + u32 cmd; - value |= (phyaddr << priv->hw->mii.addr_shift) - & priv->hw->mii.addr_mask; - value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) - & priv->hw->mii.clk_csr_mask; - if (priv->plat->has_gmac4) - value |= MII_GMAC4_READ; - - data = stmmac_mdio_read(priv, data, value); - - pm_runtime_put(priv->device); + if (priv->plat->core_type == DWMAC_CORE_GMAC4) + cmd = MII_GMAC4_READ; + else + cmd = 0; - return data; + return stmmac_mdio_read(priv, phyaddr, phyreg, cmd, 0); } /** @@ -312,54 +323,11 @@ static int stmmac_mdio_read_c22(struct mii_bus *bus, int phyaddr, int phyreg) static int stmmac_mdio_read_c45(struct mii_bus *bus, int phyaddr, int devad, int phyreg) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv = netdev_priv(ndev); - u32 value = MII_BUSY; - int data = 0; - - data = pm_runtime_get_sync(priv->device); - if (data < 0) { - pm_runtime_put_noidle(priv->device); - return data; - } - - value |= (phyaddr << priv->hw->mii.addr_shift) - & priv->hw->mii.addr_mask; - value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) - & priv->hw->mii.clk_csr_mask; - value |= MII_GMAC4_READ; - value |= MII_GMAC4_C45E; - value &= ~priv->hw->mii.reg_mask; - value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - - data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT; - - data = stmmac_mdio_read(priv, data, value); - - pm_runtime_put(priv->device); - - return data; -} - -static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value) -{ - unsigned int mii_address = priv->hw->mii.addr; - unsigned int mii_data = priv->hw->mii.data; - u32 v; - - /* Wait until any existing MII operation is complete */ - if (readl_poll_timeout(priv->ioaddr + mii_address, v, !(v & MII_BUSY), - 100, 10000)) - return -EBUSY; + struct stmmac_priv *priv = netdev_priv(bus->priv); + int data = phyreg << MII_GMAC4_REG_ADDR_SHIFT; + u32 cmd = MII_GMAC4_READ | MII_GMAC4_C45E; - /* Set the MII address register to write */ - writel(data, priv->ioaddr + mii_data); - writel(value, priv->ioaddr + mii_address); - - /* Wait until any existing MII operation is complete */ - return readl_poll_timeout(priv->ioaddr + mii_address, v, - !(v & MII_BUSY), 100, 10000); + return stmmac_mdio_read(priv, phyaddr, devad, cmd, data); } /** @@ -373,31 +341,15 @@ static int stmmac_mdio_write(struct stmmac_priv *priv, int data, u32 value) static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg, u16 phydata) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv = netdev_priv(ndev); - int ret, data = phydata; - u32 value = MII_BUSY; + struct stmmac_priv *priv = netdev_priv(bus->priv); + u32 cmd; - ret = pm_runtime_resume_and_get(priv->device); - if (ret < 0) - return ret; - - value |= (phyaddr << priv->hw->mii.addr_shift) - & priv->hw->mii.addr_mask; - value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - - value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) - & priv->hw->mii.clk_csr_mask; - if (priv->plat->has_gmac4) - value |= MII_GMAC4_WRITE; + if (priv->plat->core_type == DWMAC_CORE_GMAC4) + cmd = MII_GMAC4_WRITE; else - value |= MII_WRITE; - - ret = stmmac_mdio_write(priv, data, value); + cmd = MII_ADDR_GWRITE; - pm_runtime_put(priv->device); - - return ret; + return stmmac_mdio_write(priv, phyaddr, phyreg, cmd, phydata); } /** @@ -412,36 +364,13 @@ static int stmmac_mdio_write_c22(struct mii_bus *bus, int phyaddr, int phyreg, static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr, int devad, int phyreg, u16 phydata) { - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv = netdev_priv(ndev); - int ret, data = phydata; - u32 value = MII_BUSY; - - ret = pm_runtime_get_sync(priv->device); - if (ret < 0) { - pm_runtime_put_noidle(priv->device); - return ret; - } - - value |= (phyaddr << priv->hw->mii.addr_shift) - & priv->hw->mii.addr_mask; - value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - - value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) - & priv->hw->mii.clk_csr_mask; - - value |= MII_GMAC4_WRITE; - value |= MII_GMAC4_C45E; - value &= ~priv->hw->mii.reg_mask; - value |= (devad << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; + struct stmmac_priv *priv = netdev_priv(bus->priv); + u32 cmd = MII_GMAC4_WRITE | MII_GMAC4_C45E; + int data = phydata; data |= phyreg << MII_GMAC4_REG_ADDR_SHIFT; - ret = stmmac_mdio_write(priv, data, value); - - pm_runtime_put(priv->device); - - return ret; + return stmmac_mdio_write(priv, phyaddr, devad, cmd, data); } /** @@ -452,8 +381,7 @@ static int stmmac_mdio_write_c45(struct mii_bus *bus, int phyaddr, int stmmac_mdio_reset(struct mii_bus *bus) { #if IS_ENABLED(CONFIG_STMMAC_PLATFORM) - struct net_device *ndev = bus->priv; - struct stmmac_priv *priv = netdev_priv(ndev); + struct stmmac_priv *priv = netdev_priv(bus->priv); unsigned int mii_address = priv->hw->mii.addr; #ifdef CONFIG_OF @@ -489,7 +417,7 @@ int stmmac_mdio_reset(struct mii_bus *bus) * on MDC, so perform a dummy mdio read. To be updated for GMAC4 * if needed. */ - if (!priv->plat->has_gmac4) + if (priv->plat->core_type != DWMAC_CORE_GMAC4) writel(0, priv->ioaddr + mii_address); #endif return 0; @@ -497,12 +425,11 @@ int stmmac_mdio_reset(struct mii_bus *bus) int stmmac_pcs_setup(struct net_device *ndev) { + struct stmmac_priv *priv = netdev_priv(ndev); struct fwnode_handle *devnode, *pcsnode; struct dw_xpcs *xpcs = NULL; - struct stmmac_priv *priv; int addr, ret; - priv = netdev_priv(ndev); devnode = priv->plat->port_node; if (priv->plat->pcs_init) { @@ -547,6 +474,102 @@ void stmmac_pcs_clean(struct net_device *ndev) } /** + * stmmac_clk_csr_set - dynamically set the MDC clock + * @priv: driver private structure + * Description: this is to dynamically set the MDC clock according to the csr + * clock input. + * Return: MII register CR field value + * Note: + * If a specific clk_csr value is passed from the platform + * this means that the CSR Clock Range selection cannot be + * changed at run-time and it is fixed (as reported in the driver + * documentation). Viceversa the driver will try to set the MDC + * clock dynamically according to the actual clock input. + */ +static u32 stmmac_clk_csr_set(struct stmmac_priv *priv) +{ + unsigned long clk_rate; + u32 value = ~0; + + clk_rate = clk_get_rate(priv->plat->stmmac_clk); + + /* Platform provided default clk_csr would be assumed valid + * for all other cases except for the below mentioned ones. + * For values higher than the IEEE 802.3 specified frequency + * we can not estimate the proper divider as it is not known + * the frequency of clk_csr_i. So we do not change the default + * divider. + */ + if (clk_rate < CSR_F_35M) + value = STMMAC_CSR_20_35M; + else if (clk_rate < CSR_F_60M) + value = STMMAC_CSR_35_60M; + else if (clk_rate < CSR_F_100M) + value = STMMAC_CSR_60_100M; + else if (clk_rate < CSR_F_150M) + value = STMMAC_CSR_100_150M; + else if (clk_rate < CSR_F_250M) + value = STMMAC_CSR_150_250M; + else if (clk_rate <= CSR_F_300M) + value = STMMAC_CSR_250_300M; + else if (clk_rate < CSR_F_500M) + value = STMMAC_CSR_300_500M; + else if (clk_rate < CSR_F_800M) + value = STMMAC_CSR_500_800M; + + if (priv->plat->flags & STMMAC_FLAG_HAS_SUN8I) { + if (clk_rate > 160000000) + value = 0x03; + else if (clk_rate > 80000000) + value = 0x02; + else if (clk_rate > 40000000) + value = 0x01; + else + value = 0; + } + + if (priv->plat->core_type == DWMAC_CORE_XGMAC) { + if (clk_rate > 400000000) + value = 0x5; + else if (clk_rate > 350000000) + value = 0x4; + else if (clk_rate > 300000000) + value = 0x3; + else if (clk_rate > 250000000) + value = 0x2; + else if (clk_rate > 150000000) + value = 0x1; + else + value = 0x0; + } + + return value; +} + +static void stmmac_mdio_bus_config(struct stmmac_priv *priv) +{ + u32 value; + + /* If a specific clk_csr value is passed from the platform, this means + * that the CSR Clock Range value should not be computed from the CSR + * clock. + */ + if (priv->plat->clk_csr >= 0) + value = priv->plat->clk_csr; + else + value = stmmac_clk_csr_set(priv); + + value <<= priv->hw->mii.clk_csr_shift; + + if (value & ~priv->hw->mii.clk_csr_mask) + dev_warn(priv->device, + "clk_csr value out of range (0x%08x exceeds mask 0x%08x), truncating\n", + value, priv->hw->mii.clk_csr_mask); + + priv->gmii_address_bus_config = value & priv->hw->mii.clk_csr_mask; +} + +/** * stmmac_mdio_register * @ndev: net device structure * Description: it registers the MII bus @@ -560,12 +583,15 @@ int stmmac_mdio_register(struct net_device *ndev) struct device_node *mdio_node = priv->plat->mdio_node; struct device *dev = ndev->dev.parent; struct fwnode_handle *fixed_node; + int max_addr = PHY_MAX_ADDR - 1; struct fwnode_handle *fwnode; - int addr, found, max_addr; + struct phy_device *phydev; if (!mdio_bus_data) return 0; + stmmac_mdio_bus_config(priv); + new_bus = mdiobus_alloc(); if (!new_bus) return -ENOMEM; @@ -575,7 +601,7 @@ int stmmac_mdio_register(struct net_device *ndev) new_bus->name = "stmmac"; - if (priv->plat->has_xgmac) { + if (priv->plat->core_type == DWMAC_CORE_XGMAC) { new_bus->read = &stmmac_xgmac2_mdio_read_c22; new_bus->write = &stmmac_xgmac2_mdio_write_c22; new_bus->read_c45 = &stmmac_xgmac2_mdio_read_c45; @@ -583,25 +609,20 @@ int stmmac_mdio_register(struct net_device *ndev) if (priv->synopsys_id < DWXGMAC_CORE_2_20) { /* Right now only C22 phys are supported */ - max_addr = MII_XGMAC_MAX_C22ADDR + 1; + max_addr = MII_XGMAC_MAX_C22ADDR; /* Check if DT specified an unsupported phy addr */ if (priv->plat->phy_addr > MII_XGMAC_MAX_C22ADDR) dev_err(dev, "Unsupported phy_addr (max=%d)\n", MII_XGMAC_MAX_C22ADDR); - } else { - /* XGMAC version 2.20 onwards support 32 phy addr */ - max_addr = PHY_MAX_ADDR; } } else { new_bus->read = &stmmac_mdio_read_c22; new_bus->write = &stmmac_mdio_write_c22; - if (priv->plat->has_gmac4) { + if (priv->plat->core_type == DWMAC_CORE_GMAC4) { new_bus->read_c45 = &stmmac_mdio_read_c45; new_bus->write_c45 = &stmmac_mdio_write_c45; } - - max_addr = PHY_MAX_ADDR; } if (mdio_bus_data->needs_reset) @@ -624,7 +645,7 @@ int stmmac_mdio_register(struct net_device *ndev) } /* Looks like we need a dummy read for XGMAC only and C45 PHYs */ - if (priv->plat->has_xgmac) + if (priv->plat->core_type == DWMAC_CORE_XGMAC) stmmac_xgmac2_mdio_read_c45(new_bus, 0, 0, 0); /* If fixed-link is set, skip PHY scanning */ @@ -643,41 +664,31 @@ int stmmac_mdio_register(struct net_device *ndev) if (priv->plat->phy_node || mdio_node) goto bus_register_done; - found = 0; - for (addr = 0; addr < max_addr; addr++) { - struct phy_device *phydev = mdiobus_get_phy(new_bus, addr); - - if (!phydev) - continue; - - /* - * If an IRQ was provided to be assigned after - * the bus probe, do it here. - */ - if (!mdio_bus_data->irqs && - (mdio_bus_data->probed_phy_irq > 0)) { - new_bus->irq[addr] = mdio_bus_data->probed_phy_irq; - phydev->irq = mdio_bus_data->probed_phy_irq; - } - - /* - * If we're going to bind the MAC to this PHY bus, - * and no PHY number was provided to the MAC, - * use the one probed here. - */ - if (priv->plat->phy_addr == -1) - priv->plat->phy_addr = addr; - - phy_attached_info(phydev); - found = 1; - } - - if (!found && !mdio_node) { + phydev = phy_find_first(new_bus); + if (!phydev || phydev->mdio.addr > max_addr) { dev_warn(dev, "No PHY found\n"); err = -ENODEV; goto no_phy_found; } + /* + * If an IRQ was provided to be assigned after + * the bus probe, do it here. + */ + if (!mdio_bus_data->irqs && mdio_bus_data->probed_phy_irq > 0) { + new_bus->irq[phydev->mdio.addr] = mdio_bus_data->probed_phy_irq; + phydev->irq = mdio_bus_data->probed_phy_irq; + } + + /* + * If we're going to bind the MAC to this PHY bus, and no PHY number + * was provided to the MAC, use the one probed here. + */ + if (priv->plat->phy_addr == -1) + priv->plat->phy_addr = phydev->mdio.addr; + + phy_attached_info(phydev); + bus_register_done: priv->mii = new_bus; @@ -709,3 +720,17 @@ int stmmac_mdio_unregister(struct net_device *ndev) return 0; } + +void stmmac_mdio_lock(struct stmmac_priv *priv) +{ + if (priv->mii) + mutex_lock(&priv->mii->mdio_lock); +} +EXPORT_SYMBOL_GPL(stmmac_mdio_lock); + +void stmmac_mdio_unlock(struct stmmac_priv *priv) +{ + if (priv->mii) + mutex_unlock(&priv->mii->mdio_lock); +} +EXPORT_SYMBOL_GPL(stmmac_mdio_unlock); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 9c1b54b701f7..270ad066ced3 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -14,6 +14,7 @@ #include <linux/dmi.h> #include "stmmac.h" +#include "stmmac_libpci.h" struct stmmac_pci_info { int (*setup)(struct pci_dev *pdev, struct plat_stmmacenet_data *plat); @@ -21,31 +22,12 @@ struct stmmac_pci_info { static void common_default_data(struct plat_stmmacenet_data *plat) { - plat->clk_csr = 2; /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ - plat->has_gmac = 1; + /* clk_csr_i = 20-35MHz & MDC = clk_csr_i/16 */ + plat->clk_csr = STMMAC_CSR_20_35M; + plat->core_type = DWMAC_CORE_GMAC; plat->force_sf_dma_mode = 1; plat->mdio_bus_data->needs_reset = true; - - /* Set default value for multicast hash bins */ - plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - - /* Set the maxmtu to a default of JUMBO_LEN */ - plat->maxmtu = JUMBO_LEN; - - /* Set default number of RX and TX queues to use */ - plat->tx_queues_to_use = 1; - plat->rx_queues_to_use = 1; - - /* Disable Priority config by default */ - plat->tx_queues_cfg[0].use_prio = false; - plat->rx_queues_cfg[0].use_prio = false; - - /* Disable RX queues routing by default */ - plat->rx_queues_cfg[0].pkt_route = 0x0; } static int stmmac_default_data(struct pci_dev *pdev, @@ -74,28 +56,18 @@ static int snps_gmac5_default_data(struct pci_dev *pdev, { int i; - plat->clk_csr = 5; - plat->has_gmac4 = 1; + plat->clk_csr = STMMAC_CSR_250_300M; + plat->core_type = DWMAC_CORE_GMAC4; plat->force_sf_dma_mode = 1; plat->flags |= STMMAC_FLAG_TSO_EN; plat->pmt = 1; - /* Set default value for multicast hash bins */ - plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - - /* Set the maxmtu to a default of JUMBO_LEN */ - plat->maxmtu = JUMBO_LEN; - /* Set default number of RX and TX queues to use */ plat->tx_queues_to_use = 4; plat->rx_queues_to_use = 4; plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR; for (i = 0; i < plat->tx_queues_to_use; i++) { - plat->tx_queues_cfg[i].use_prio = false; plat->tx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB; plat->tx_queues_cfg[i].weight = 25; if (i > 0) @@ -103,15 +75,10 @@ static int snps_gmac5_default_data(struct pci_dev *pdev, } plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP; - for (i = 0; i < plat->rx_queues_to_use; i++) { - plat->rx_queues_cfg[i].use_prio = false; + for (i = 0; i < plat->rx_queues_to_use; i++) plat->rx_queues_cfg[i].mode_to_use = MTL_QUEUE_DCB; - plat->rx_queues_cfg[i].pkt_route = 0x0; - plat->rx_queues_cfg[i].chan = i; - } plat->bus_id = 1; - plat->phy_addr = -1; plat->phy_interface = PHY_INTERFACE_MODE_GMII; plat->dma_cfg->pbl = 32; @@ -126,10 +93,8 @@ static int snps_gmac5_default_data(struct pci_dev *pdev, plat->axi->axi_rd_osr_lmt = 31; plat->axi->axi_fb = false; - plat->axi->axi_blen[0] = 4; - plat->axi->axi_blen[1] = 8; - plat->axi->axi_blen[2] = 16; - plat->axi->axi_blen[3] = 32; + plat->axi->axi_blen_regval = DMA_AXI_BLEN4 | DMA_AXI_BLEN8 | + DMA_AXI_BLEN16 | DMA_AXI_BLEN32; return 0; } @@ -159,7 +124,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev, int ret; int i; - plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + plat = stmmac_plat_dat_alloc(&pdev->dev); if (!plat) return -ENOMEM; @@ -217,6 +182,9 @@ static int stmmac_pci_probe(struct pci_dev *pdev, plat->safety_feat_cfg->prtyen = 1; plat->safety_feat_cfg->tmouten = 1; + plat->suspend = stmmac_pci_plat_suspend; + plat->resume = stmmac_pci_plat_resume; + return stmmac_dvr_probe(&pdev->dev, plat, &res); } @@ -231,43 +199,6 @@ static void stmmac_pci_remove(struct pci_dev *pdev) stmmac_dvr_remove(&pdev->dev); } -static int __maybe_unused stmmac_pci_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - ret = stmmac_suspend(dev); - if (ret) - return ret; - - ret = pci_save_state(pdev); - if (ret) - return ret; - - pci_disable_device(pdev); - pci_wake_from_d3(pdev, true); - return 0; -} - -static int __maybe_unused stmmac_pci_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - int ret; - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - return stmmac_resume(dev); -} - -static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume); - /* synthetic ID, no official vendor */ #define PCI_VENDOR_ID_STMMAC 0x0700 @@ -289,7 +220,7 @@ static struct pci_driver stmmac_pci_driver = { .probe = stmmac_pci_probe, .remove = stmmac_pci_remove, .driver = { - .pm = &stmmac_pm_ops, + .pm = &stmmac_simple_pm_ops, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c new file mode 100644 index 000000000000..e2f531c11986 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "stmmac.h" +#include "stmmac_pcs.h" + +static int dwmac_integrated_pcs_enable(struct phylink_pcs *pcs) +{ + struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs); + + stmmac_mac_irq_modify(spcs->priv, 0, spcs->int_mask); + + return 0; +} + +static void dwmac_integrated_pcs_disable(struct phylink_pcs *pcs) +{ + struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs); + + stmmac_mac_irq_modify(spcs->priv, spcs->int_mask, 0); +} + +static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs, + unsigned int neg_mode, + struct phylink_link_state *state) +{ + state->link = false; +} + +static int dwmac_integrated_pcs_config(struct phylink_pcs *pcs, + unsigned int neg_mode, + phy_interface_t interface, + const unsigned long *advertising, + bool permit_pause_to_mac) +{ + struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs); + + dwmac_ctrl_ane(spcs->base, 0, 1, spcs->priv->hw->reverse_sgmii_enable); + + return 0; +} + +static const struct phylink_pcs_ops dwmac_integrated_pcs_ops = { + .pcs_enable = dwmac_integrated_pcs_enable, + .pcs_disable = dwmac_integrated_pcs_disable, + .pcs_get_state = dwmac_integrated_pcs_get_state, + .pcs_config = dwmac_integrated_pcs_config, +}; + +int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset, + u32 int_mask) +{ + struct stmmac_pcs *spcs; + + spcs = devm_kzalloc(priv->device, sizeof(*spcs), GFP_KERNEL); + if (!spcs) + return -ENOMEM; + + spcs->priv = priv; + spcs->base = priv->ioaddr + offset; + spcs->int_mask = int_mask; + spcs->pcs.ops = &dwmac_integrated_pcs_ops; + + __set_bit(PHY_INTERFACE_MODE_SGMII, spcs->pcs.supported_interfaces); + + priv->integrated_pcs = spcs; + + return 0; +} diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index 1bdf87b237c4..cda93894168e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -9,6 +9,7 @@ #ifndef __STMMAC_PCS_H__ #define __STMMAC_PCS_H__ +#include <linux/phylink.h> #include <linux/slab.h> #include <linux/io.h> #include "common.h" @@ -16,6 +17,8 @@ /* PCS registers (AN/TBI/SGMII/RGMII) offsets */ #define GMAC_AN_CTRL(x) (x) /* AN control */ #define GMAC_AN_STATUS(x) (x + 0x4) /* AN status */ + +/* ADV, LPA and EXP are only available for the TBI and RTBI interfaces */ #define GMAC_ANE_ADV(x) (x + 0x8) /* ANE Advertisement */ #define GMAC_ANE_LPA(x) (x + 0xc) /* ANE link partener ability */ #define GMAC_ANE_EXP(x) (x + 0x10) /* ANE expansion */ @@ -44,6 +47,24 @@ #define GMAC_ANE_RFE_SHIFT 12 #define GMAC_ANE_ACK BIT(14) +struct stmmac_priv; + +struct stmmac_pcs { + struct stmmac_priv *priv; + void __iomem *base; + u32 int_mask; + struct phylink_pcs pcs; +}; + +static inline struct stmmac_pcs * +phylink_pcs_to_stmmac_pcs(struct phylink_pcs *pcs) +{ + return container_of(pcs, struct stmmac_pcs, pcs); +} + +int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset, + u32 int_mask); + /** * dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR * @ioaddr: IO registers pointer @@ -80,13 +101,12 @@ static inline void dwmac_pcs_isr(void __iomem *ioaddr, u32 reg, * @reg: Base address of the AN Control Register. * @ane: to enable the auto-negotiation * @srgmi_ral: to manage MAC-2-MAC SGMII connections. - * @loopback: to cause the PHY to loopback tx data into rx path. * Description: this is the main function to configure the AN control register * and init the ANE, select loopback (usually for debugging purpose) and * configure SGMII RAL. */ static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane, - bool srgmi_ral, bool loopback) + bool srgmi_ral) { u32 value = readl(ioaddr + GMAC_AN_CTRL(reg)); @@ -102,39 +122,6 @@ static inline void dwmac_ctrl_ane(void __iomem *ioaddr, u32 reg, bool ane, if (srgmi_ral) value |= GMAC_AN_CTRL_SGMRAL; - if (loopback) - value |= GMAC_AN_CTRL_ELE; - writel(value, ioaddr + GMAC_AN_CTRL(reg)); } - -/** - * dwmac_get_adv_lp - Get ADV and LP cap - * @ioaddr: IO registers pointer - * @reg: Base address of the AN Control Register. - * @adv_lp: structure to store the adv,lp status - * Description: this is to expose the ANE advertisement and Link partner ability - * status to ethtool support. - */ -static inline void dwmac_get_adv_lp(void __iomem *ioaddr, u32 reg, - struct rgmii_adv *adv_lp) -{ - u32 value = readl(ioaddr + GMAC_ANE_ADV(reg)); - - if (value & GMAC_ANE_FD) - adv_lp->duplex = DUPLEX_FULL; - if (value & GMAC_ANE_HD) - adv_lp->duplex |= DUPLEX_HALF; - - adv_lp->pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT; - - value = readl(ioaddr + GMAC_ANE_LPA(reg)); - - if (value & GMAC_ANE_FD) - adv_lp->lp_duplex = DUPLEX_FULL; - if (value & GMAC_ANE_HD) - adv_lp->lp_duplex = DUPLEX_HALF; - - adv_lp->lp_pause = (value & GMAC_ANE_PSE) >> GMAC_ANE_PSE_SHIFT; -} #endif /* __STMMAC_PCS_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index c73eff6a56b8..8979a50b5507 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -60,7 +60,7 @@ static int dwmac1000_validate_mcast_bins(struct device *dev, int mcast_bins) * Description: * This function validates the number of Unicast address entries supported * by a particular Synopsys 10/100/1000 controller. The Synopsys controller - * supports 1..32, 64, or 128 Unicast filter entries for it's Unicast filter + * supports 1..32, 64, or 128 Unicast filter entries for its Unicast filter * logic. This function validates a valid, supported configuration is * selected, and defaults to 1 Unicast address if an unsupported * configuration is selected. @@ -95,6 +95,7 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev) { struct device_node *np; struct stmmac_axi *axi; + u32 axi_blen[AXI_BLEN]; np = of_parse_phandle(pdev->dev.of_node, "snps,axi-config", 0); if (!np) @@ -117,7 +118,8 @@ static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev) axi->axi_wr_osr_lmt = 1; if (of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt)) axi->axi_rd_osr_lmt = 1; - of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN); + of_property_read_u32_array(np, "snps,blen", axi_blen, AXI_BLEN); + stmmac_axi_blen_to_mask(&axi->axi_blen_regval, axi_blen, AXI_BLEN); of_node_put(np); return axi; @@ -137,13 +139,6 @@ static int stmmac_mtl_setup(struct platform_device *pdev, u8 queue = 0; int ret = 0; - /* For backwards-compatibility with device trees that don't have any - * snps,mtl-rx-config or snps,mtl-tx-config properties, we fall back - * to one RX and TX queues each. - */ - plat->rx_queues_to_use = 1; - plat->tx_queues_to_use = 1; - /* First Queue must always be in DCB mode. As MTL_QUEUE_DCB = 1 we need * to always set this, otherwise Queue will be classified as AVB * (because MTL_QUEUE_AVB = 0). @@ -162,9 +157,8 @@ static int stmmac_mtl_setup(struct platform_device *pdev, } /* Processing RX queues common config */ - if (of_property_read_u32(rx_node, "snps,rx-queues-to-use", - &plat->rx_queues_to_use)) - plat->rx_queues_to_use = 1; + of_property_read_u32(rx_node, "snps,rx-queues-to-use", + &plat->rx_queues_to_use); if (of_property_read_bool(rx_node, "snps,rx-sched-sp")) plat->rx_sched_algorithm = MTL_RX_ALGORITHM_SP; @@ -185,18 +179,13 @@ static int stmmac_mtl_setup(struct platform_device *pdev, else plat->rx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB; - if (of_property_read_u32(q_node, "snps,map-to-dma-channel", - &plat->rx_queues_cfg[queue].chan)) - plat->rx_queues_cfg[queue].chan = queue; + of_property_read_u32(q_node, "snps,map-to-dma-channel", + &plat->rx_queues_cfg[queue].chan); /* TODO: Dynamic mapping to be included in the future */ - if (of_property_read_u32(q_node, "snps,priority", - &plat->rx_queues_cfg[queue].prio)) { - plat->rx_queues_cfg[queue].prio = 0; - plat->rx_queues_cfg[queue].use_prio = false; - } else { + if (!of_property_read_u32(q_node, "snps,priority", + &plat->rx_queues_cfg[queue].prio)) plat->rx_queues_cfg[queue].use_prio = true; - } /* RX queue specific packet type routing */ if (of_property_read_bool(q_node, "snps,route-avcp")) @@ -209,8 +198,6 @@ static int stmmac_mtl_setup(struct platform_device *pdev, plat->rx_queues_cfg[queue].pkt_route = PACKET_UPQ; else if (of_property_read_bool(q_node, "snps,route-multi-broad")) plat->rx_queues_cfg[queue].pkt_route = PACKET_MCBCQ; - else - plat->rx_queues_cfg[queue].pkt_route = 0x0; queue++; } @@ -221,9 +208,8 @@ static int stmmac_mtl_setup(struct platform_device *pdev, } /* Processing TX queues common config */ - if (of_property_read_u32(tx_node, "snps,tx-queues-to-use", - &plat->tx_queues_to_use)) - plat->tx_queues_to_use = 1; + of_property_read_u32(tx_node, "snps,tx-queues-to-use", + &plat->tx_queues_to_use); if (of_property_read_bool(tx_node, "snps,tx-sched-wrr")) plat->tx_sched_algorithm = MTL_TX_ALGORITHM_WRR; @@ -268,13 +254,9 @@ static int stmmac_mtl_setup(struct platform_device *pdev, plat->tx_queues_cfg[queue].mode_to_use = MTL_QUEUE_DCB; } - if (of_property_read_u32(q_node, "snps,priority", - &plat->tx_queues_cfg[queue].prio)) { - plat->tx_queues_cfg[queue].prio = 0; - plat->tx_queues_cfg[queue].use_prio = false; - } else { + if (!of_property_read_u32(q_node, "snps,priority", + &plat->tx_queues_cfg[queue].prio)) plat->tx_queues_cfg[queue].use_prio = true; - } plat->tx_queues_cfg[queue].coe_unsupported = of_property_read_bool(q_node, "snps,coe-unsupported"); @@ -410,6 +392,7 @@ static const char * const stmmac_gmac4_compats[] = { "snps,dwmac-4.00", "snps,dwmac-4.10a", "snps,dwmac-4.20a", + "snps,dwmac-5.00a", "snps,dwmac-5.10a", "snps,dwmac-5.20", "snps,dwmac-5.30a", @@ -430,11 +413,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) struct device_node *np = pdev->dev.of_node; struct plat_stmmacenet_data *plat; struct stmmac_dma_cfg *dma_cfg; + static int bus_id = -ENODEV; int phy_mode; void *ret; int rc; - plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + plat = stmmac_plat_dat_alloc(&pdev->dev); if (!plat) return ERR_PTR(-ENOMEM); @@ -451,8 +435,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) return ERR_PTR(phy_mode); plat->phy_interface = phy_mode; + rc = stmmac_of_get_mac_mode(np); - plat->mac_interface = rc < 0 ? plat->phy_interface : rc; + if (rc >= 0 && rc != phy_mode) + dev_warn(&pdev->dev, + "\"mac-mode\" property used for %s but differs to \"phy-mode\" of %s, and will be ignored. Please report.\n", + phy_modes(rc), phy_modes(phy_mode)); /* Some wrapper drivers still rely on phy_node. Let's save it while * they are not converted to phylink. */ @@ -465,16 +453,15 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) of_property_read_u32(np, "max-speed", &plat->max_speed); plat->bus_id = of_alias_get_id(np, "ethernet"); - if (plat->bus_id < 0) - plat->bus_id = 0; - - /* Default to phy auto-detection */ - plat->phy_addr = -1; + if (plat->bus_id < 0) { + if (bus_id < 0) + bus_id = of_alias_get_highest_id("ethernet"); + /* No ethernet alias found, init at -1 so first bus_id is 0 */ + if (bus_id < 0) + bus_id = -1; + plat->bus_id = ++bus_id; + } - /* Default to get clk_csr from stmmac_clk_csr_set(), - * or get clk_csr from device tree. - */ - plat->clk_csr = -1; if (of_property_read_u32(np, "snps,clk-csr", &plat->clk_csr)) of_property_read_u32(np, "clk_csr", &plat->clk_csr); @@ -503,17 +490,6 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) plat->flags |= STMMAC_FLAG_EN_TX_LPI_CLOCKGATING; } - /* Set the maxmtu to a default of JUMBO_LEN in case the - * parameter is not present in the device tree. - */ - plat->maxmtu = JUMBO_LEN; - - /* Set default value for multicast hash bins */ - plat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat->unicast_filter_entries = 1; - /* * Currently only the properties needed on SPEAr600 * are provided. All other properties should be added @@ -540,12 +516,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) &pdev->dev, plat->unicast_filter_entries); plat->multicast_filter_bins = dwmac1000_validate_mcast_bins( &pdev->dev, plat->multicast_filter_bins); - plat->has_gmac = 1; + plat->core_type = DWMAC_CORE_GMAC; plat->pmt = 1; } if (of_device_is_compatible(np, "snps,dwmac-3.40a")) { - plat->has_gmac = 1; + plat->core_type = DWMAC_CORE_GMAC; plat->enh_desc = 1; plat->tx_coe = 1; plat->bugged_jumbo = 1; @@ -553,8 +529,7 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) } if (of_device_compatible_match(np, stmmac_gmac4_compats)) { - plat->has_gmac4 = 1; - plat->has_gmac = 0; + plat->core_type = DWMAC_CORE_GMAC4; plat->pmt = 1; if (of_property_read_bool(np, "snps,tso")) plat->flags |= STMMAC_FLAG_TSO_EN; @@ -568,10 +543,12 @@ stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) } if (of_device_is_compatible(np, "snps,dwxgmac")) { - plat->has_xgmac = 1; + plat->core_type = DWMAC_CORE_XGMAC; plat->pmt = 1; if (of_property_read_bool(np, "snps,tso")) plat->flags |= STMMAC_FLAG_TSO_EN; + of_property_read_u32(np, "snps,multicast-filter-bins", + &plat->multicast_filter_bins); } dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), @@ -709,6 +686,17 @@ devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac) #endif /* CONFIG_OF */ EXPORT_SYMBOL_GPL(devm_stmmac_probe_config_dt); +struct clk *stmmac_pltfr_find_clk(struct plat_stmmacenet_data *plat_dat, + const char *name) +{ + for (int i = 0; i < plat_dat->num_clks; i++) + if (strcmp(plat_dat->clks[i].id, name) == 0) + return plat_dat->clks[i].clk; + + return NULL; +} +EXPORT_SYMBOL_GPL(stmmac_pltfr_find_clk); + int stmmac_get_platform_resources(struct platform_device *pdev, struct stmmac_resources *stmmac_res) { @@ -761,33 +749,49 @@ EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); /** * stmmac_pltfr_init - * @pdev: pointer to the platform device + * @dev: pointer to the device structure * @plat: driver data platform structure * Description: Call the platform's init callback (if any) and propagate * the return value. */ -static int stmmac_pltfr_init(struct platform_device *pdev, +static int stmmac_pltfr_init(struct device *dev, struct plat_stmmacenet_data *plat) { int ret = 0; if (plat->init) - ret = plat->init(pdev, plat->bsp_priv); + ret = plat->init(dev, plat->bsp_priv); return ret; } /** * stmmac_pltfr_exit - * @pdev: pointer to the platform device + * @dev: pointer to the device structure * @plat: driver data platform structure * Description: Call the platform's exit callback (if any). */ -static void stmmac_pltfr_exit(struct platform_device *pdev, +static void stmmac_pltfr_exit(struct device *dev, struct plat_stmmacenet_data *plat) { if (plat->exit) - plat->exit(pdev, plat->bsp_priv); + plat->exit(dev, plat->bsp_priv); +} + +static int stmmac_plat_suspend(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + + stmmac_pltfr_exit(dev, priv->plat); + + return 0; +} + +static int stmmac_plat_resume(struct device *dev, void *bsp_priv) +{ + struct stmmac_priv *priv = netdev_priv(dev_get_drvdata(dev)); + + return stmmac_pltfr_init(dev, priv->plat); } /** @@ -802,19 +806,12 @@ int stmmac_pltfr_probe(struct platform_device *pdev, struct plat_stmmacenet_data *plat, struct stmmac_resources *res) { - int ret; + if (!plat->suspend && plat->exit) + plat->suspend = stmmac_plat_suspend; + if (!plat->resume && plat->init) + plat->resume = stmmac_plat_resume; - ret = stmmac_pltfr_init(pdev, plat); - if (ret) - return ret; - - ret = stmmac_dvr_probe(&pdev->dev, plat, res); - if (ret) { - stmmac_pltfr_exit(pdev, plat); - return ret; - } - - return ret; + return stmmac_dvr_probe(&pdev->dev, plat, res); } EXPORT_SYMBOL_GPL(stmmac_pltfr_probe); @@ -856,54 +853,40 @@ EXPORT_SYMBOL_GPL(devm_stmmac_pltfr_probe); */ void stmmac_pltfr_remove(struct platform_device *pdev) { - struct net_device *ndev = platform_get_drvdata(pdev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct plat_stmmacenet_data *plat = priv->plat; - stmmac_dvr_remove(&pdev->dev); - stmmac_pltfr_exit(pdev, plat); } EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); -/** - * stmmac_pltfr_suspend - * @dev: device pointer - * Description: this function is invoked when suspend the driver and it direcly - * call the main suspend function and then, if required, on some platform, it - * can call an exit helper. - */ -static int __maybe_unused stmmac_pltfr_suspend(struct device *dev) +static int stmmac_bus_clks_config(struct stmmac_priv *priv, bool enabled) { + struct plat_stmmacenet_data *plat_dat = priv->plat; int ret; - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct platform_device *pdev = to_platform_device(dev); - - ret = stmmac_suspend(dev); - stmmac_pltfr_exit(pdev, priv->plat); - return ret; -} - -/** - * stmmac_pltfr_resume - * @dev: device pointer - * Description: this function is invoked when resume the driver before calling - * the main resume function, on some platforms, it can call own init helper - * if required. - */ -static int __maybe_unused stmmac_pltfr_resume(struct device *dev) -{ - struct net_device *ndev = dev_get_drvdata(dev); - struct stmmac_priv *priv = netdev_priv(ndev); - struct platform_device *pdev = to_platform_device(dev); - int ret; - - ret = stmmac_pltfr_init(pdev, priv->plat); - if (ret) - return ret; + if (enabled) { + ret = clk_prepare_enable(plat_dat->stmmac_clk); + if (ret) + return ret; + ret = clk_prepare_enable(plat_dat->pclk); + if (ret) { + clk_disable_unprepare(plat_dat->stmmac_clk); + return ret; + } + if (plat_dat->clks_config) { + ret = plat_dat->clks_config(plat_dat->bsp_priv, enabled); + if (ret) { + clk_disable_unprepare(plat_dat->stmmac_clk); + clk_disable_unprepare(plat_dat->pclk); + return ret; + } + } + } else { + clk_disable_unprepare(plat_dat->stmmac_clk); + clk_disable_unprepare(plat_dat->pclk); + if (plat_dat->clks_config) + plat_dat->clks_config(plat_dat->bsp_priv, enabled); + } - return stmmac_resume(dev); + return 0; } static int __maybe_unused stmmac_runtime_suspend(struct device *dev) @@ -933,7 +916,7 @@ static int __maybe_unused stmmac_pltfr_noirq_suspend(struct device *dev) if (!netif_running(ndev)) return 0; - if (!device_may_wakeup(priv->device) || !priv->plat->pmt) { + if (!priv->wolopts) { /* Disable clock in case of PWM is off */ clk_disable_unprepare(priv->plat->clk_ptp_ref); @@ -954,7 +937,7 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev) if (!netif_running(ndev)) return 0; - if (!device_may_wakeup(priv->device) || !priv->plat->pmt) { + if (!priv->wolopts) { /* enable the clk previously disabled */ ret = pm_runtime_force_resume(dev); if (ret) @@ -973,7 +956,7 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev) } const struct dev_pm_ops stmmac_pltfr_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_suspend, stmmac_pltfr_resume) + SET_SYSTEM_SLEEP_PM_OPS(stmmac_suspend, stmmac_resume) SET_RUNTIME_PM_OPS(stmmac_runtime_suspend, stmmac_runtime_resume, NULL) SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(stmmac_pltfr_noirq_suspend, stmmac_pltfr_noirq_resume) }; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 72dc1a32e46d..6e6561e29d6e 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -14,6 +14,9 @@ struct plat_stmmacenet_data * devm_stmmac_probe_config_dt(struct platform_device *pdev, u8 *mac); +struct clk *stmmac_pltfr_find_clk(struct plat_stmmacenet_data *plat_dat, + const char *name); + int stmmac_get_platform_resources(struct platform_device *pdev, struct stmmac_resources *stmmac_res); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c index 429b2d357813..3e30172fa129 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c @@ -10,6 +10,8 @@ #include "stmmac.h" #include "stmmac_ptp.h" +#define PTP_SAFE_TIME_OFFSET_NS 500000 + /** * stmmac_adjust_freq * @@ -55,7 +57,7 @@ static int stmmac_adjust_time(struct ptp_clock_info *ptp, s64 delta) bool xmac, est_rst = false; int ret; - xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac; + xmac = dwmac_is_xmac(priv->plat->core_type); if (delta < 0) { neg_adj = 1; @@ -171,7 +173,11 @@ static int stmmac_enable(struct ptp_clock_info *ptp, u32 acr_value; switch (rq->type) { - case PTP_CLK_REQ_PEROUT: + case PTP_CLK_REQ_PEROUT: { + struct timespec64 curr_time; + u64 target_ns = 0; + u64 ns = 0; + /* Reject requests with unsupported flags */ if (rq->perout.flags) return -EOPNOTSUPP; @@ -180,6 +186,31 @@ static int stmmac_enable(struct ptp_clock_info *ptp, cfg->start.tv_sec = rq->perout.start.sec; cfg->start.tv_nsec = rq->perout.start.nsec; + + /* A time set in the past won't trigger the start of the flexible PPS generation for + * the GMAC5. For some reason it does for the GMAC4 but setting a time in the past + * should be addressed anyway. Therefore, any value set it the past is considered as + * an offset compared to the current MAC system time. + * Be aware that an offset too low may not trigger flexible PPS generation + * if time spent in this configuration makes the targeted time already outdated. + * To address this, add a safe time offset. + */ + if (!cfg->start.tv_sec && cfg->start.tv_nsec < PTP_SAFE_TIME_OFFSET_NS) + cfg->start.tv_nsec += PTP_SAFE_TIME_OFFSET_NS; + + target_ns = cfg->start.tv_nsec + ((u64)cfg->start.tv_sec * NSEC_PER_SEC); + + stmmac_get_systime(priv, priv->ptpaddr, &ns); + if (ns > TIME64_MAX - PTP_SAFE_TIME_OFFSET_NS) + return -EINVAL; + + curr_time = ns_to_timespec64(ns); + if (target_ns < ns + PTP_SAFE_TIME_OFFSET_NS) { + cfg->start = timespec64_add_safe(cfg->start, curr_time); + if (cfg->start.tv_sec == TIME64_MAX) + return -EINVAL; + } + cfg->period.tv_sec = rq->perout.period.sec; cfg->period.tv_nsec = rq->perout.period.nsec; @@ -190,6 +221,7 @@ static int stmmac_enable(struct ptp_clock_info *ptp, priv->systime_flags); write_unlock_irqrestore(&priv->ptp_lock, flags); break; + } case PTP_CLK_REQ_EXTTS: { u8 channel; @@ -247,10 +279,7 @@ static int stmmac_get_syncdevicetime(ktime_t *device, { struct stmmac_priv *priv = (struct stmmac_priv *)ctx; - if (priv->plat->crosststamp) - return priv->plat->crosststamp(device, system, ctx); - else - return -EOPNOTSUPP; + return priv->plat->crosststamp(device, system, ctx); } static int stmmac_getcrosststamp(struct ptp_clock_info *ptp, @@ -278,7 +307,6 @@ const struct ptp_clock_info stmmac_ptp_clock_ops = { .gettime64 = stmmac_get_time, .settime64 = stmmac_set_time, .enable = stmmac_enable, - .getcrosststamp = stmmac_getcrosststamp, }; /* structure describing a PTP hardware clock */ @@ -296,7 +324,6 @@ const struct ptp_clock_info dwmac1000_ptp_clock_ops = { .gettime64 = stmmac_get_time, .settime64 = stmmac_set_time, .enable = dwmac1000_ptp_enable, - .getcrosststamp = stmmac_getcrosststamp, }; /** @@ -317,7 +344,7 @@ void stmmac_ptp_register(struct stmmac_priv *priv) /* Calculate the clock domain crossing (CDC) error if necessary */ priv->plat->cdc_error_adj = 0; - if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) + if (priv->plat->core_type == DWMAC_CORE_GMAC4) priv->plat->cdc_error_adj = (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate; /* Update the ptp clock parameters based on feature discovery, when @@ -332,6 +359,9 @@ void stmmac_ptp_register(struct stmmac_priv *priv) if (priv->plat->ptp_max_adj) priv->ptp_clock_ops.max_adj = priv->plat->ptp_max_adj; + if (priv->plat->crosststamp) + priv->ptp_clock_ops.getcrosststamp = stmmac_getcrosststamp; + rwlock_init(&priv->ptp_lock); mutex_init(&priv->aux_ts_lock); @@ -340,8 +370,12 @@ void stmmac_ptp_register(struct stmmac_priv *priv) if (IS_ERR(priv->ptp_clock)) { netdev_err(priv->dev, "ptp_clock_register failed\n"); priv->ptp_clock = NULL; - } else if (priv->ptp_clock) + } + + if (priv->ptp_clock) netdev_info(priv->dev, "registered PTP clock\n"); + else + mutex_destroy(&priv->aux_ts_lock); } /** @@ -357,7 +391,7 @@ void stmmac_ptp_unregister(struct stmmac_priv *priv) priv->ptp_clock = NULL; pr_debug("Removed PTP HW clock successfully on %s\n", priv->dev->name); - } - mutex_destroy(&priv->aux_ts_lock); + mutex_destroy(&priv->aux_ts_lock); + } } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c index a01bc394d1ac..e90a2c469b9a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c @@ -1721,7 +1721,7 @@ static int stmmac_test_sph(struct stmmac_priv *priv) struct stmmac_packet_attrs attr = { }; int ret; - if (!priv->sph) + if (!priv->sph_active) return -EOPNOTSUPP; /* Check for UDP first */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 694d6ee14381..d78652718599 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -262,10 +262,10 @@ static int tc_init(struct stmmac_priv *priv) unsigned int count; int ret, i; - if (dma_cap->l3l4fnum) { - priv->flow_entries_max = dma_cap->l3l4fnum; + priv->flow_entries_max = dma_cap->l3l4fnum; + if (priv->flow_entries_max) { priv->flow_entries = devm_kcalloc(priv->device, - dma_cap->l3l4fnum, + priv->flow_entries_max, sizeof(*priv->flow_entries), GFP_KERNEL); if (!priv->flow_entries) @@ -981,7 +981,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv, if (qopt->cmd == TAPRIO_CMD_DESTROY) goto disable; - if (qopt->num_entries >= dep) + if (qopt->num_entries > dep) return -EINVAL; if (!qopt->cycle_time) return -ERANGE; @@ -1012,7 +1012,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv, s64 delta_ns = qopt->entries[i].interval; u32 gates = qopt->entries[i].gate_mask; - if (delta_ns > GENMASK(wid, 0)) + if (delta_ns > GENMASK(wid - 1, 0)) return -ERANGE; if (gates > GENMASK(31 - wid, 0)) return -ERANGE; @@ -1080,6 +1080,7 @@ disable: for (i = 0; i < priv->plat->tx_queues_to_use; i++) { priv->xstats.max_sdu_txq_drop[i] = 0; priv->xstats.mtl_est_txq_hlbf[i] = 0; + priv->xstats.mtl_est_txq_hlbs[i] = 0; } mutex_unlock(&priv->est_lock); } @@ -1097,7 +1098,8 @@ static void tc_taprio_stats(struct stmmac_priv *priv, for (i = 0; i < priv->plat->tx_queues_to_use; i++) window_drops += priv->xstats.max_sdu_txq_drop[i] + - priv->xstats.mtl_est_txq_hlbf[i]; + priv->xstats.mtl_est_txq_hlbf[i] + + priv->xstats.mtl_est_txq_hlbs[i]; qopt->stats.window_drops = window_drops; /* Transmission overrun doesn't happen for stmmac, hence always 0 */ @@ -1111,7 +1113,8 @@ static void tc_taprio_queue_stats(struct stmmac_priv *priv, int queue = qopt->queue_stats.queue; q_stats->stats.window_drops = priv->xstats.max_sdu_txq_drop[queue] + - priv->xstats.mtl_est_txq_hlbf[queue]; + priv->xstats.mtl_est_txq_hlbf[queue] + + priv->xstats.mtl_est_txq_hlbs[queue]; /* Transmission overrun doesn't happen for stmmac, hence always 0 */ q_stats->stats.tx_overruns = 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c new file mode 100644 index 000000000000..b18404dd5a8b --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.c @@ -0,0 +1,375 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025, Altera Corporation + * stmmac VLAN (802.1Q) handling + */ + +#include "stmmac.h" +#include "stmmac_vlan.h" + +static void vlan_write_single(struct net_device *dev, u16 vid) +{ + void __iomem *ioaddr = (void __iomem *)dev->base_addr; + u32 val; + + val = readl(ioaddr + VLAN_TAG); + val &= ~VLAN_TAG_VID; + val |= VLAN_TAG_ETV | vid; + + writel(val, ioaddr + VLAN_TAG); +} + +static int vlan_write_filter(struct net_device *dev, + struct mac_device_info *hw, + u8 index, u32 data) +{ + void __iomem *ioaddr = (void __iomem *)dev->base_addr; + int ret; + u32 val; + + if (index >= hw->num_vlan) + return -EINVAL; + + writel(data, ioaddr + VLAN_TAG_DATA); + + val = readl(ioaddr + VLAN_TAG); + val &= ~(VLAN_TAG_CTRL_OFS_MASK | + VLAN_TAG_CTRL_CT | + VLAN_TAG_CTRL_OB); + val |= (index << VLAN_TAG_CTRL_OFS_SHIFT) | VLAN_TAG_CTRL_OB; + + writel(val, ioaddr + VLAN_TAG); + + ret = readl_poll_timeout(ioaddr + VLAN_TAG, val, + !(val & VLAN_TAG_CTRL_OB), + 1000, 500000); + if (ret) { + netdev_err(dev, "Timeout accessing MAC_VLAN_Tag_Filter\n"); + return -EBUSY; + } + + return 0; +} + +static int vlan_add_hw_rx_fltr(struct net_device *dev, + struct mac_device_info *hw, + __be16 proto, u16 vid) +{ + int index = -1; + u32 val = 0; + int i, ret; + + if (vid > 4095) + return -EINVAL; + + /* Single Rx VLAN Filter */ + if (hw->num_vlan == 1) { + /* For single VLAN filter, VID 0 means VLAN promiscuous */ + if (vid == 0) { + netdev_warn(dev, "Adding VLAN ID 0 is not supported\n"); + return -EPERM; + } + + if (hw->vlan_filter[0] & VLAN_TAG_VID) { + netdev_err(dev, "Only single VLAN ID supported\n"); + return -EPERM; + } + + hw->vlan_filter[0] = vid; + vlan_write_single(dev, vid); + + return 0; + } + + /* Extended Rx VLAN Filter Enable */ + val |= VLAN_TAG_DATA_ETV | VLAN_TAG_DATA_VEN | vid; + + for (i = 0; i < hw->num_vlan; i++) { + if (hw->vlan_filter[i] == val) + return 0; + else if (!(hw->vlan_filter[i] & VLAN_TAG_DATA_VEN)) + index = i; + } + + if (index == -1) { + netdev_err(dev, "MAC_VLAN_Tag_Filter full (size: %0u)\n", + hw->num_vlan); + return -EPERM; + } + + ret = vlan_write_filter(dev, hw, index, val); + + if (!ret) + hw->vlan_filter[index] = val; + + return ret; +} + +static int vlan_del_hw_rx_fltr(struct net_device *dev, + struct mac_device_info *hw, + __be16 proto, u16 vid) +{ + int i, ret = 0; + + /* Single Rx VLAN Filter */ + if (hw->num_vlan == 1) { + if ((hw->vlan_filter[0] & VLAN_TAG_VID) == vid) { + hw->vlan_filter[0] = 0; + vlan_write_single(dev, 0); + } + return 0; + } + + /* Extended Rx VLAN Filter Enable */ + for (i = 0; i < hw->num_vlan; i++) { + if ((hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) && + ((hw->vlan_filter[i] & VLAN_TAG_DATA_VID) == vid)) { + ret = vlan_write_filter(dev, hw, i, 0); + + if (!ret) + hw->vlan_filter[i] = 0; + else + return ret; + } + } + + return ret; +} + +static void vlan_restore_hw_rx_fltr(struct net_device *dev, + struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + u32 hash; + u32 val; + int i; + + /* Single Rx VLAN Filter */ + if (hw->num_vlan == 1) { + vlan_write_single(dev, hw->vlan_filter[0]); + return; + } + + /* Extended Rx VLAN Filter Enable */ + for (i = 0; i < hw->num_vlan; i++) { + if (hw->vlan_filter[i] & VLAN_TAG_DATA_VEN) { + val = hw->vlan_filter[i]; + vlan_write_filter(dev, hw, i, val); + } + } + + hash = readl(ioaddr + VLAN_HASH_TABLE); + if (hash & VLAN_VLHT) { + value = readl(ioaddr + VLAN_TAG); + value |= VLAN_VTHM; + writel(value, ioaddr + VLAN_TAG); + } +} + +static void vlan_update_hash(struct mac_device_info *hw, u32 hash, + u16 perfect_match, bool is_double) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + + writel(hash, ioaddr + VLAN_HASH_TABLE); + + value = readl(ioaddr + VLAN_TAG); + + if (hash) { + value |= VLAN_VTHM | VLAN_ETV; + if (is_double) { + value |= VLAN_EDVLP; + value |= VLAN_ESVL; + value |= VLAN_DOVLTC; + } + + writel(value, ioaddr + VLAN_TAG); + } else if (perfect_match) { + u32 value = VLAN_ETV; + + if (is_double) { + value |= VLAN_EDVLP; + value |= VLAN_ESVL; + value |= VLAN_DOVLTC; + } + + writel(value | perfect_match, ioaddr + VLAN_TAG); + } else { + value &= ~(VLAN_VTHM | VLAN_ETV); + value &= ~(VLAN_EDVLP | VLAN_ESVL); + value &= ~VLAN_DOVLTC; + value &= ~VLAN_VID; + + writel(value, ioaddr + VLAN_TAG); + } +} + +static void vlan_enable(struct mac_device_info *hw, u32 type) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + + value = readl(ioaddr + VLAN_INCL); + value |= VLAN_VLTI; + value &= ~VLAN_CSVL; /* Only use CVLAN */ + value &= ~VLAN_VLC; + value |= (type << VLAN_VLC_SHIFT) & VLAN_VLC; + writel(value, ioaddr + VLAN_INCL); +} + +static void vlan_rx_hw(struct mac_device_info *hw, + struct dma_desc *rx_desc, struct sk_buff *skb) +{ + if (hw->desc->get_rx_vlan_valid(rx_desc)) { + u16 vid = hw->desc->get_rx_vlan_tci(rx_desc); + + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); + } +} + +static void vlan_set_hw_mode(struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value = readl(ioaddr + VLAN_TAG); + + value &= ~VLAN_TAG_CTRL_EVLS_MASK; + + if (hw->hw_vlan_en) + /* Always strip VLAN on Receive */ + value |= VLAN_TAG_STRIP_ALL; + else + /* Do not strip VLAN on Receive */ + value |= VLAN_TAG_STRIP_NONE; + + /* Enable outer VLAN Tag in Rx DMA descriptor */ + value |= VLAN_TAG_CTRL_EVLRXS; + writel(value, ioaddr + VLAN_TAG); +} + +static void dwxgmac2_update_vlan_hash(struct mac_device_info *hw, u32 hash, + u16 perfect_match, bool is_double) +{ + void __iomem *ioaddr = hw->pcsr; + + writel(hash, ioaddr + VLAN_HASH_TABLE); + + if (hash) { + u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); + + value |= XGMAC_FILTER_VTFE; + + writel(value, ioaddr + XGMAC_PACKET_FILTER); + + value = readl(ioaddr + VLAN_TAG); + + value |= VLAN_VTHM | VLAN_ETV; + if (is_double) { + value |= VLAN_EDVLP; + value |= VLAN_ESVL; + value |= VLAN_DOVLTC; + } else { + value &= ~VLAN_EDVLP; + value &= ~VLAN_ESVL; + value &= ~VLAN_DOVLTC; + } + + value &= ~VLAN_VID; + writel(value, ioaddr + VLAN_TAG); + } else if (perfect_match) { + u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); + + value |= XGMAC_FILTER_VTFE; + + writel(value, ioaddr + XGMAC_PACKET_FILTER); + + value = readl(ioaddr + VLAN_TAG); + + value &= ~VLAN_VTHM; + value |= VLAN_ETV; + if (is_double) { + value |= VLAN_EDVLP; + value |= VLAN_ESVL; + value |= VLAN_DOVLTC; + } else { + value &= ~VLAN_EDVLP; + value &= ~VLAN_ESVL; + value &= ~VLAN_DOVLTC; + } + + value &= ~VLAN_VID; + writel(value | perfect_match, ioaddr + VLAN_TAG); + } else { + u32 value = readl(ioaddr + XGMAC_PACKET_FILTER); + + value &= ~XGMAC_FILTER_VTFE; + + writel(value, ioaddr + XGMAC_PACKET_FILTER); + + value = readl(ioaddr + VLAN_TAG); + + value &= ~(VLAN_VTHM | VLAN_ETV); + value &= ~(VLAN_EDVLP | VLAN_ESVL); + value &= ~VLAN_DOVLTC; + value &= ~VLAN_VID; + + writel(value, ioaddr + VLAN_TAG); + } +} + +const struct stmmac_vlan_ops dwmac_vlan_ops = { + .update_vlan_hash = vlan_update_hash, + .enable_vlan = vlan_enable, + .add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr, + .del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr, + .restore_hw_vlan_rx_fltr = vlan_restore_hw_rx_fltr, + .rx_hw_vlan = vlan_rx_hw, + .set_hw_vlan_mode = vlan_set_hw_mode, +}; + +const struct stmmac_vlan_ops dwxlgmac2_vlan_ops = { + .update_vlan_hash = dwxgmac2_update_vlan_hash, + .enable_vlan = vlan_enable, +}; + +const struct stmmac_vlan_ops dwxgmac210_vlan_ops = { + .update_vlan_hash = dwxgmac2_update_vlan_hash, + .enable_vlan = vlan_enable, + .add_hw_vlan_rx_fltr = vlan_add_hw_rx_fltr, + .del_hw_vlan_rx_fltr = vlan_del_hw_rx_fltr, + .restore_hw_vlan_rx_fltr = vlan_restore_hw_rx_fltr, + .rx_hw_vlan = vlan_rx_hw, + .set_hw_vlan_mode = vlan_set_hw_mode, +}; + +u32 stmmac_get_num_vlan(void __iomem *ioaddr) +{ + u32 val, num_vlan; + + val = readl(ioaddr + HW_FEATURE3); + switch (val & VLAN_HW_FEAT_NRVF) { + case 0: + num_vlan = 1; + break; + case 1: + num_vlan = 4; + break; + case 2: + num_vlan = 8; + break; + case 3: + num_vlan = 16; + break; + case 4: + num_vlan = 24; + break; + case 5: + num_vlan = 32; + break; + default: + num_vlan = 1; + } + + return num_vlan; +} diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.h new file mode 100644 index 000000000000..c24f89a9049b --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_vlan.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2025, Altera Corporation + * stmmac VLAN(802.1Q) handling + */ + +#ifndef __STMMAC_VLAN_H__ +#define __STMMAC_VLAN_H__ + +#include <linux/bitfield.h> +#include "dwxgmac2.h" + +#define VLAN_TAG 0x00000050 +#define VLAN_TAG_DATA 0x00000054 +#define VLAN_HASH_TABLE 0x00000058 +#define VLAN_INCL 0x00000060 + +/* MAC VLAN */ +#define VLAN_EDVLP BIT(26) +#define VLAN_VTHM BIT(25) +#define VLAN_DOVLTC BIT(20) +#define VLAN_ESVL BIT(18) +#define VLAN_ETV BIT(16) +#define VLAN_VID GENMASK(15, 0) +#define VLAN_VLTI BIT(20) +#define VLAN_CSVL BIT(19) +#define VLAN_VLC GENMASK(17, 16) +#define VLAN_VLC_SHIFT 16 +#define VLAN_VLHT GENMASK(15, 0) + +/* MAC VLAN Tag */ +#define VLAN_TAG_VID GENMASK(15, 0) +#define VLAN_TAG_ETV BIT(16) + +/* MAC VLAN Tag Control */ +#define VLAN_TAG_CTRL_OB BIT(0) +#define VLAN_TAG_CTRL_CT BIT(1) +#define VLAN_TAG_CTRL_OFS_MASK GENMASK(6, 2) +#define VLAN_TAG_CTRL_OFS_SHIFT 2 +#define VLAN_TAG_CTRL_EVLS_MASK GENMASK(22, 21) +#define VLAN_TAG_CTRL_EVLS_SHIFT 21 +#define VLAN_TAG_CTRL_EVLRXS BIT(24) + +#define VLAN_TAG_STRIP_NONE FIELD_PREP(VLAN_TAG_CTRL_EVLS_MASK, 0x0) +#define VLAN_TAG_STRIP_PASS FIELD_PREP(VLAN_TAG_CTRL_EVLS_MASK, 0x1) +#define VLAN_TAG_STRIP_FAIL FIELD_PREP(VLAN_TAG_CTRL_EVLS_MASK, 0x2) +#define VLAN_TAG_STRIP_ALL FIELD_PREP(VLAN_TAG_CTRL_EVLS_MASK, 0x3) + +/* MAC VLAN Tag Data/Filter */ +#define VLAN_TAG_DATA_VID GENMASK(15, 0) +#define VLAN_TAG_DATA_VEN BIT(16) +#define VLAN_TAG_DATA_ETV BIT(17) + +/* MAC VLAN HW FEAT */ +#define HW_FEATURE3 0x00000128 +#define VLAN_HW_FEAT_NRVF GENMASK(2, 0) + +extern const struct stmmac_vlan_ops dwmac_vlan_ops; +extern const struct stmmac_vlan_ops dwxgmac210_vlan_ops; +extern const struct stmmac_vlan_ops dwxlgmac2_vlan_ops; + +u32 stmmac_get_num_vlan(void __iomem *ioaddr); + +#endif /* __STMMAC_VLAN_H__ */ diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c index aa6f16d3df64..d7e4db7224b0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c @@ -129,7 +129,7 @@ int stmmac_xdp_set_prog(struct stmmac_priv *priv, struct bpf_prog *prog, bpf_prog_put(old_prog); /* Disable RX SPH for XDP operation */ - priv->sph = priv->sph_cap && !stmmac_xdp_is_enabled(priv); + priv->sph_active = priv->sph_capable && !stmmac_xdp_is_enabled(priv); if (if_running && need_update) stmmac_xdp_open(dev); |
