From 3789b1f5a0760bce2f56993685a3f7e7202d41d0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 22 Nov 2015 19:06:51 +0000 Subject: ipq806x: update stmmac to the version from linux 4.3 Signed-off-by: Felix Fietkau SVN-Revision: 47593 --- .../patches-4.1/701-stmmac_update_to_4.3.patch | 2355 ++++++++++++++++++++ 1 file changed, 2355 insertions(+) create mode 100644 target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch (limited to 'target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch') diff --git a/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch b/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch new file mode 100644 index 0000000000..22450d4bbe --- /dev/null +++ b/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch @@ -0,0 +1,2355 @@ +--- a/drivers/net/ethernet/stmicro/Kconfig ++++ b/drivers/net/ethernet/stmicro/Kconfig +@@ -7,9 +7,7 @@ config NET_VENDOR_STMICRO + default y + depends on HAS_IOMEM + ---help--- +- If you have a network (Ethernet) card belonging to this class, say Y +- and read the Ethernet-HOWTO, available from +- . ++ If you have a network (Ethernet) card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all +--- a/drivers/net/ethernet/stmicro/stmmac/Kconfig ++++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig +@@ -16,6 +16,7 @@ if STMMAC_ETH + config STMMAC_PLATFORM + tristate "STMMAC Platform bus support" + depends on STMMAC_ETH ++ select MFD_SYSCON + default y + ---help--- + This selects the platform specific bus support for the stmmac driver. +@@ -26,6 +27,95 @@ config STMMAC_PLATFORM + + If unsure, say N. + ++if STMMAC_PLATFORM ++ ++config DWMAC_GENERIC ++ tristate "Generic driver for DWMAC" ++ default STMMAC_PLATFORM ++ ---help--- ++ Generic DWMAC driver for platforms that don't require any ++ platform specific code to function or is using platform ++ data for setup. ++ ++config DWMAC_IPQ806X ++ tristate "QCA IPQ806x DWMAC support" ++ default ARCH_QCOM ++ depends on OF ++ select MFD_SYSCON ++ help ++ Support for QCA IPQ806X DWMAC Ethernet. ++ ++ This selects the IPQ806x SoC glue layer support for the stmmac ++ device driver. This driver does not use any of the hardware ++ acceleration features available on this SoC. Network devices ++ will behave like standard non-accelerated ethernet interfaces. ++ ++config DWMAC_LPC18XX ++ tristate "NXP LPC18xx/43xx DWMAC support" ++ default ARCH_LPC18XX ++ depends on OF ++ select MFD_SYSCON ++ ---help--- ++ Support for NXP LPC18xx/43xx DWMAC Ethernet. ++ ++config DWMAC_MESON ++ tristate "Amlogic Meson dwmac support" ++ default ARCH_MESON ++ depends on OF ++ help ++ Support for Ethernet controller on Amlogic Meson SoCs. ++ ++ This selects the Amlogic Meson SoC glue layer support for ++ the stmmac device driver. This driver is used for Meson6 and ++ Meson8 SoCs. ++ ++config DWMAC_ROCKCHIP ++ tristate "Rockchip dwmac support" ++ default ARCH_ROCKCHIP ++ depends on OF ++ select MFD_SYSCON ++ help ++ Support for Ethernet controller on Rockchip RK3288 SoC. ++ ++ This selects the Rockchip RK3288 SoC glue layer support for ++ the stmmac device driver. ++ ++config DWMAC_SOCFPGA ++ tristate "SOCFPGA dwmac support" ++ default ARCH_SOCFPGA ++ depends on OF ++ select MFD_SYSCON ++ help ++ Support for ethernet controller on Altera SOCFPGA ++ ++ This selects the Altera SOCFPGA SoC glue layer support ++ for the stmmac device driver. This driver is used for ++ arria5 and cyclone5 FPGA SoCs. ++ ++config DWMAC_STI ++ tristate "STi GMAC support" ++ default ARCH_STI ++ depends on OF ++ select MFD_SYSCON ++ ---help--- ++ Support for ethernet controller on STi SOCs. ++ ++ This selects STi SoC glue layer support for the stmmac ++ device driver. This driver is used on for the STi series ++ SOCs GMAC ethernet controller. ++ ++config DWMAC_SUNXI ++ tristate "Allwinner GMAC support" ++ default ARCH_SUNXI ++ depends on OF ++ ---help--- ++ Support for Allwinner A20/A31 GMAC ethernet controllers. ++ ++ This selects Allwinner SoC glue layer support for the ++ stmmac device driver. This driver is used for A20/A31 ++ GMAC ethernet controller. ++endif ++ + config STMMAC_PCI + tristate "STMMAC PCI bus support" + depends on STMMAC_ETH && PCI +--- a/drivers/net/ethernet/stmicro/stmmac/Makefile ++++ b/drivers/net/ethernet/stmicro/stmmac/Makefile +@@ -4,9 +4,17 @@ stmmac-objs:= stmmac_main.o stmmac_ethto + dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ + mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y) + +-obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o +-stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \ +- dwmac-sti.o dwmac-socfpga.o dwmac-rk.o ++# Ordering matters. Generic driver must be last. ++obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o ++obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o ++obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o ++obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o ++obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o ++obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o ++obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o ++obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o ++obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o ++stmmac-platform-objs:= stmmac_platform.o + + obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o + stmmac-pci-objs:= stmmac_pci.o +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c +@@ -0,0 +1,81 @@ ++/* ++ * Generic DWMAC platform driver ++ * ++ * Copyright (C) 2007-2011 STMicroelectronics Ltd ++ * Copyright (C) 2015 Joachim Eastwood ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++ ++#include "stmmac.h" ++#include "stmmac_platform.h" ++ ++static int dwmac_generic_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ int ret; ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ if (pdev->dev.of_node) { ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) { ++ dev_err(&pdev->dev, "dt configuration failed\n"); ++ return PTR_ERR(plat_dat); ++ } ++ } else { ++ plat_dat = dev_get_platdata(&pdev->dev); ++ if (!plat_dat) { ++ dev_err(&pdev->dev, "no platform data provided\n"); ++ return -EINVAL; ++ } ++ ++ /* Set default value for multicast hash bins */ ++ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; ++ ++ /* Set default value for unicast filter entries */ ++ plat_dat->unicast_filter_entries = 1; ++ } ++ ++ /* Custom initialisation (if needed) */ ++ if (plat_dat->init) { ++ ret = plat_dat->init(pdev, plat_dat->bsp_priv); ++ if (ret) ++ return ret; ++ } ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++} ++ ++static const struct of_device_id dwmac_generic_match[] = { ++ { .compatible = "st,spear600-gmac"}, ++ { .compatible = "snps,dwmac-3.610"}, ++ { .compatible = "snps,dwmac-3.70a"}, ++ { .compatible = "snps,dwmac-3.710"}, ++ { .compatible = "snps,dwmac"}, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, dwmac_generic_match); ++ ++static struct platform_driver dwmac_generic_driver = { ++ .probe = dwmac_generic_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = STMMAC_RESOURCE_NAME, ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = of_match_ptr(dwmac_generic_match), ++ }, ++}; ++module_platform_driver(dwmac_generic_driver); ++ ++MODULE_DESCRIPTION("Generic dwmac driver"); ++MODULE_LICENSE("GPL v2"); +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c +@@ -0,0 +1,373 @@ ++/* ++ * Qualcomm Atheros IPQ806x GMAC glue layer ++ * ++ * Copyright (C) 2015 The Linux Foundation ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES ++ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ++ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "stmmac_platform.h" ++ ++#define NSS_COMMON_CLK_GATE 0x8 ++#define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x) ++#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2)) ++#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2)) ++#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x) ++#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x) ++ ++#define NSS_COMMON_CLK_DIV0 0xC ++#define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8) ++#define NSS_COMMON_CLK_DIV_MASK 0x7f ++ ++#define NSS_COMMON_CLK_SRC_CTRL 0x14 ++#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (x) ++/* Mode is coded on 1 bit but is different depending on the MAC ID: ++ * MAC0: QSGMII=0 RGMII=1 ++ * MAC1: QSGMII=0 SGMII=0 RGMII=1 ++ * MAC2 & MAC3: QSGMII=0 SGMII=1 ++ */ ++#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1 ++#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0) ++ ++#define NSS_COMMON_MACSEC_CTL 0x28 ++#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x) ++ ++#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4)) ++#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19) ++#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16) ++#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8 ++#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0 ++#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f ++ ++#define NSS_COMMON_CLK_DIV_RGMII_1000 1 ++#define NSS_COMMON_CLK_DIV_RGMII_100 9 ++#define NSS_COMMON_CLK_DIV_RGMII_10 99 ++#define NSS_COMMON_CLK_DIV_SGMII_1000 0 ++#define NSS_COMMON_CLK_DIV_SGMII_100 4 ++#define NSS_COMMON_CLK_DIV_SGMII_10 49 ++ ++#define QSGMII_PCS_MODE_CTL 0x68 ++#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7) ++ ++#define QSGMII_PCS_CAL_LCKDT_CTL 0x120 ++#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19) ++ ++/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */ ++#define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \ ++ (0x13c + (4 * (x - 2)))) ++#define QSGMII_PHY_CDR_EN BIT(0) ++#define QSGMII_PHY_RX_FRONT_EN BIT(1) ++#define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2) ++#define QSGMII_PHY_TX_DRIVER_EN BIT(3) ++#define QSGMII_PHY_QSGMII_EN BIT(7) ++#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12 ++#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7 ++#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18 ++#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3 ++#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20 ++#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3 ++#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22 ++#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3 ++#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28 ++#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf ++ ++struct ipq806x_gmac { ++ struct platform_device *pdev; ++ struct regmap *nss_common; ++ struct regmap *qsgmii_csr; ++ uint32_t id; ++ struct clk *core_clk; ++ phy_interface_t phy_mode; ++}; ++ ++static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed) ++{ ++ struct device *dev = &gmac->pdev->dev; ++ int div; ++ ++ switch (speed) { ++ case SPEED_1000: ++ div = NSS_COMMON_CLK_DIV_SGMII_1000; ++ break; ++ ++ case SPEED_100: ++ div = NSS_COMMON_CLK_DIV_SGMII_100; ++ break; ++ ++ case SPEED_10: ++ div = NSS_COMMON_CLK_DIV_SGMII_10; ++ break; ++ ++ default: ++ dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed); ++ return -EINVAL; ++ } ++ ++ return div; ++} ++ ++static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed) ++{ ++ struct device *dev = &gmac->pdev->dev; ++ int div; ++ ++ switch (speed) { ++ case SPEED_1000: ++ div = NSS_COMMON_CLK_DIV_RGMII_1000; ++ break; ++ ++ case SPEED_100: ++ div = NSS_COMMON_CLK_DIV_RGMII_100; ++ break; ++ ++ case SPEED_10: ++ div = NSS_COMMON_CLK_DIV_RGMII_10; ++ break; ++ ++ default: ++ dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed); ++ return -EINVAL; ++ } ++ ++ return div; ++} ++ ++static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed) ++{ ++ uint32_t clk_bits, val; ++ int div; ++ ++ switch (gmac->phy_mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ div = get_clk_div_rgmii(gmac, speed); ++ clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) | ++ NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id); ++ break; ++ ++ case PHY_INTERFACE_MODE_SGMII: ++ div = get_clk_div_sgmii(gmac, speed); ++ clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) | ++ NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id); ++ break; ++ ++ default: ++ dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n", ++ phy_modes(gmac->phy_mode)); ++ return -EINVAL; ++ } ++ ++ /* Disable the clocks */ ++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val); ++ val &= ~clk_bits; ++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); ++ ++ /* Set the divider */ ++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val); ++ val &= ~(NSS_COMMON_CLK_DIV_MASK ++ << NSS_COMMON_CLK_DIV_OFFSET(gmac->id)); ++ val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id); ++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val); ++ ++ /* Enable the clock back */ ++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val); ++ val |= clk_bits; ++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); ++ ++ return 0; ++} ++ ++static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac) ++{ ++ struct device *dev = &gmac->pdev->dev; ++ ++ gmac->phy_mode = of_get_phy_mode(dev->of_node); ++ if (gmac->phy_mode < 0) { ++ dev_err(dev, "missing phy mode property\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) { ++ dev_err(dev, "missing qcom id property\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ /* The GMACs are called 1 to 4 in the documentation, but to simplify the ++ * code and keep it consistent with the Linux convention, we'll number ++ * them from 0 to 3 here. ++ */ ++ if (gmac->id < 0 || gmac->id > 3) { ++ dev_err(dev, "invalid gmac id\n"); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ gmac->core_clk = devm_clk_get(dev, "stmmaceth"); ++ if (IS_ERR(gmac->core_clk)) { ++ dev_err(dev, "missing stmmaceth clk property\n"); ++ return gmac->core_clk; ++ } ++ clk_set_rate(gmac->core_clk, 266000000); ++ ++ /* Setup the register map for the nss common registers */ ++ gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node, ++ "qcom,nss-common"); ++ if (IS_ERR(gmac->nss_common)) { ++ dev_err(dev, "missing nss-common node\n"); ++ return gmac->nss_common; ++ } ++ ++ /* Setup the register map for the qsgmii csr registers */ ++ gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node, ++ "qcom,qsgmii-csr"); ++ if (IS_ERR(gmac->qsgmii_csr)) { ++ dev_err(dev, "missing qsgmii-csr node\n"); ++ return gmac->qsgmii_csr; ++ } ++ ++ return NULL; ++} ++ ++static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed) ++{ ++ struct ipq806x_gmac *gmac = priv; ++ ++ ipq806x_gmac_set_speed(gmac, speed); ++} ++ ++static int ipq806x_gmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ struct device *dev = &pdev->dev; ++ struct ipq806x_gmac *gmac; ++ int val; ++ void *err; ++ ++ val = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (val) ++ return val; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ ++ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); ++ if (!gmac) ++ return -ENOMEM; ++ ++ gmac->pdev = pdev; ++ ++ err = ipq806x_gmac_of_parse(gmac); ++ if (IS_ERR(err)) { ++ dev_err(dev, "device tree parsing error\n"); ++ return PTR_ERR(err); ++ } ++ ++ regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL, ++ QSGMII_PCS_CAL_LCKDT_CTL_RST); ++ ++ /* Inter frame gap is set to 12 */ ++ val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET | ++ 12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET; ++ /* We also initiate an AXI low power exit request */ ++ val |= NSS_COMMON_GMAC_CTL_CSYS_REQ; ++ switch (gmac->phy_mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL; ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL; ++ break; ++ default: ++ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", ++ phy_modes(gmac->phy_mode)); ++ return -EINVAL; ++ } ++ regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val); ++ ++ /* Configure the clock src according to the mode */ ++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val); ++ val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id)); ++ switch (gmac->phy_mode) { ++ case PHY_INTERFACE_MODE_RGMII: ++ val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) << ++ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id); ++ break; ++ case PHY_INTERFACE_MODE_SGMII: ++ val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) << ++ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id); ++ break; ++ default: ++ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n", ++ phy_modes(gmac->phy_mode)); ++ return -EINVAL; ++ } ++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val); ++ ++ /* Enable PTP clock */ ++ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val); ++ val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id); ++ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val); ++ ++ if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) { ++ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id), ++ QSGMII_PHY_CDR_EN | ++ QSGMII_PHY_RX_FRONT_EN | ++ QSGMII_PHY_RX_SIGNAL_DETECT_EN | ++ QSGMII_PHY_TX_DRIVER_EN | ++ QSGMII_PHY_QSGMII_EN | ++ 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | ++ 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET | ++ 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET | ++ 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET | ++ 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET); ++ } ++ ++ plat_dat->has_gmac = true; ++ plat_dat->bsp_priv = gmac; ++ plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed; ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++} ++ ++static const struct of_device_id ipq806x_gmac_dwmac_match[] = { ++ { .compatible = "qcom,ipq806x-gmac" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match); ++ ++static struct platform_driver ipq806x_gmac_dwmac_driver = { ++ .probe = ipq806x_gmac_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = "ipq806x-gmac-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = ipq806x_gmac_dwmac_match, ++ }, ++}; ++module_platform_driver(ipq806x_gmac_dwmac_driver); ++ ++MODULE_AUTHOR("Mathieu Olivari "); ++MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer"); ++MODULE_LICENSE("Dual BSD/GPL"); +--- /dev/null ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c +@@ -0,0 +1,86 @@ ++/* ++ * DWMAC glue for NXP LPC18xx/LPC43xx Ethernet ++ * ++ * Copyright (C) 2015 Joachim Eastwood ++ * ++ * This file is licensed under the terms of the GNU General Public ++ * License version 2. This program is licensed "as is" without any ++ * warranty of any kind, whether express or implied. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "stmmac_platform.h" ++ ++/* 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 ++ ++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; ++ int ret; ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ ++ plat_dat->has_gmac = true; ++ ++ reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); ++ if (IS_ERR(reg)) { ++ dev_err(&pdev->dev, "syscon lookup failed\n"); ++ return PTR_ERR(reg); ++ } ++ ++ if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { ++ ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII; ++ } else if (plat_dat->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; ++ } ++ ++ regmap_update_bits(reg, LPC18XX_CREG_CREG6, ++ LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++} ++ ++static const struct of_device_id lpc18xx_dwmac_match[] = { ++ { .compatible = "nxp,lpc1850-dwmac" }, ++ { } ++}; ++MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); ++ ++static struct platform_driver lpc18xx_dwmac_driver = { ++ .probe = lpc18xx_dwmac_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = "lpc18xx-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = lpc18xx_dwmac_match, ++ }, ++}; ++module_platform_driver(lpc18xx_dwmac_driver); ++ ++MODULE_AUTHOR("Joachim Eastwood "); ++MODULE_DESCRIPTION("DWMAC glue for LPC18xx/43xx Ethernet"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -46,24 +47,54 @@ static void meson6_dwmac_fix_mac_speed(v + writel(val, dwmac->reg); + } + +-static void *meson6_dwmac_setup(struct platform_device *pdev) ++static int meson6_dwmac_probe(struct platform_device *pdev) + { ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; + struct meson_dwmac *dwmac; + struct resource *res; ++ int ret; ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + dwmac->reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dwmac->reg)) +- return ERR_CAST(dwmac->reg); ++ return PTR_ERR(dwmac->reg); ++ ++ plat_dat->bsp_priv = dwmac; ++ plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; + +- return dwmac; ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + } + +-const struct stmmac_of_data meson6_dwmac_data = { +- .setup = meson6_dwmac_setup, +- .fix_mac_speed = meson6_dwmac_fix_mac_speed, ++static const struct of_device_id meson6_dwmac_match[] = { ++ { .compatible = "amlogic,meson6-dwmac" }, ++ { } + }; ++MODULE_DEVICE_TABLE(of, meson6_dwmac_match); ++ ++static struct platform_driver meson6_dwmac_driver = { ++ .probe = meson6_dwmac_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = "meson6-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = meson6_dwmac_match, ++ }, ++}; ++module_platform_driver(meson6_dwmac_driver); ++ ++MODULE_AUTHOR("Beniamino Galvani "); ++MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer"); ++MODULE_LICENSE("GPL v2"); +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +@@ -22,17 +22,31 @@ + #include + #include + #include ++#include + #include + #include ++#include + #include + #include + #include + #include + ++#include "stmmac_platform.h" ++ ++struct rk_priv_data; ++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); ++}; ++ + struct rk_priv_data { + struct platform_device *pdev; + int phy_iface; + struct regulator *regulator; ++ const struct rk_gmac_ops *ops; + + bool clk_enabled; + bool clock_input; +@@ -60,103 +74,228 @@ struct rk_priv_data { + + #define RK3288_GRF_SOC_CON1 0x0248 + #define RK3288_GRF_SOC_CON3 0x0250 +-#define RK3288_GRF_GPIO3D_E 0x01ec +-#define RK3288_GRF_GPIO4A_E 0x01f0 +-#define RK3288_GRF_GPIO4B_E 0x01f4 + + /*RK3288_GRF_SOC_CON1*/ +-#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8)) +-#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8)) +-#define GMAC_FLOW_CTRL GRF_BIT(9) +-#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9) +-#define GMAC_SPEED_10M GRF_CLR_BIT(10) +-#define GMAC_SPEED_100M GRF_BIT(10) +-#define GMAC_RMII_CLK_25M GRF_BIT(11) +-#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11) +-#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13)) +-#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13)) +-#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13)) +-#define GMAC_RMII_MODE GRF_BIT(14) +-#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) ++#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_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_RMII_MODE GRF_BIT(14) ++#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14) + + /*RK3288_GRF_SOC_CON3*/ +-#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) +-#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14) +-#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15) +-#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15) +-#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7) +-#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0) ++#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14) ++#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) + +-static void set_to_rgmii(struct rk_priv_data *bsp_priv, +- int tx_delay, int rx_delay) ++static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv, ++ int tx_delay, int rx_delay) + { + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { +- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ dev_err(dev, "Missing rockchip,grf property\n"); + return; + } + + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, +- GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR); ++ RK3288_GMAC_PHY_INTF_SEL_RGMII | ++ RK3288_GMAC_RMII_MODE_CLR); + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3, +- GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE | +- GMAC_CLK_RX_DL_CFG(rx_delay) | +- GMAC_CLK_TX_DL_CFG(tx_delay)); ++ RK3288_GMAC_RXCLK_DLY_ENABLE | ++ RK3288_GMAC_TXCLK_DLY_ENABLE | ++ RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) | ++ RK3288_GMAC_CLK_TX_DL_CFG(tx_delay)); + } + +-static void set_to_rmii(struct rk_priv_data *bsp_priv) ++static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv) + { + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { +- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ dev_err(dev, "Missing rockchip,grf property\n"); + return; + } + + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, +- GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE); ++ RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE); + } + +-static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) ++static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed) + { + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { +- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ dev_err(dev, "Missing rockchip,grf property\n"); + return; + } + + if (speed == 10) +- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M); ++ 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, GMAC_CLK_25M); ++ 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, GMAC_CLK_125M); ++ 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 void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) ++static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) + { + struct device *dev = &bsp_priv->pdev->dev; + + if (IS_ERR(bsp_priv->grf)) { +- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ dev_err(dev, "Missing rockchip,grf property\n"); + return; + } + + if (speed == 10) { + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, +- GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M); ++ RK3288_GMAC_RMII_CLK_2_5M | ++ RK3288_GMAC_SPEED_10M); + } else if (speed == 100) { + regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, +- GMAC_RMII_CLK_25M | GMAC_SPEED_100M); ++ RK3288_GMAC_RMII_CLK_25M | ++ RK3288_GMAC_SPEED_100M); ++ } else { ++ dev_err(dev, "unknown speed value for RMII! speed=%d", 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, ++}; ++ ++#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_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_RMII_MODE GRF_BIT(6) ++#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6) ++ ++/* RK3368_GRF_SOC_CON16 */ ++#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7) ++#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) ++ ++static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv, ++ int tx_delay, int rx_delay) ++{ ++ struct device *dev = &bsp_priv->pdev->dev; ++ ++ if (IS_ERR(bsp_priv->grf)) { ++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ return; ++ } ++ ++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, ++ RK3368_GMAC_PHY_INTF_SEL_RGMII | ++ RK3368_GMAC_RMII_MODE_CLR); ++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16, ++ RK3368_GMAC_RXCLK_DLY_ENABLE | ++ RK3368_GMAC_TXCLK_DLY_ENABLE | ++ RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) | ++ RK3368_GMAC_CLK_TX_DL_CFG(tx_delay)); ++} ++ ++static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv) ++{ ++ struct device *dev = &bsp_priv->pdev->dev; ++ ++ if (IS_ERR(bsp_priv->grf)) { ++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ return; ++ } ++ ++ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15, ++ RK3368_GMAC_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 (IS_ERR(bsp_priv->grf)) { ++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ return; ++ } ++ ++ 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 void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed) ++{ ++ struct device *dev = &bsp_priv->pdev->dev; ++ ++ if (IS_ERR(bsp_priv->grf)) { ++ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__); ++ return; ++ } ++ ++ 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); + } + } + ++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, ++}; ++ + static int gmac_clk_init(struct rk_priv_data *bsp_priv) + { + struct device *dev = &bsp_priv->pdev->dev; +@@ -165,46 +304,46 @@ static int gmac_clk_init(struct rk_priv_ + + bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx"); + if (IS_ERR(bsp_priv->mac_clk_rx)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "mac_clk_rx"); ++ dev_err(dev, "cannot get clock %s\n", ++ "mac_clk_rx"); + + bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx"); + if (IS_ERR(bsp_priv->mac_clk_tx)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "mac_clk_tx"); ++ dev_err(dev, "cannot get clock %s\n", ++ "mac_clk_tx"); + + bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac"); + if (IS_ERR(bsp_priv->aclk_mac)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "aclk_mac"); ++ dev_err(dev, "cannot get clock %s\n", ++ "aclk_mac"); + + bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac"); + if (IS_ERR(bsp_priv->pclk_mac)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "pclk_mac"); ++ dev_err(dev, "cannot get clock %s\n", ++ "pclk_mac"); + + bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth"); + if (IS_ERR(bsp_priv->clk_mac)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "stmmaceth"); ++ dev_err(dev, "cannot get clock %s\n", ++ "stmmaceth"); + + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { + bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref"); + if (IS_ERR(bsp_priv->clk_mac_ref)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "clk_mac_ref"); ++ dev_err(dev, "cannot get clock %s\n", ++ "clk_mac_ref"); + + if (!bsp_priv->clock_input) { + bsp_priv->clk_mac_refout = + devm_clk_get(dev, "clk_mac_refout"); + if (IS_ERR(bsp_priv->clk_mac_refout)) +- dev_err(dev, "%s: cannot get clock %s\n", +- __func__, "clk_mac_refout"); ++ dev_err(dev, "cannot get clock %s\n", ++ "clk_mac_refout"); + } + } + + if (bsp_priv->clock_input) { +- dev_info(dev, "%s: clock input from PHY\n", __func__); ++ dev_info(dev, "clock input from PHY\n"); + } else { + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) + clk_set_rate(bsp_priv->clk_mac, 50000000); +@@ -291,26 +430,25 @@ static int phy_power_on(struct rk_priv_d + struct device *dev = &bsp_priv->pdev->dev; + + if (!ldo) { +- dev_err(dev, "%s: no regulator found\n", __func__); ++ dev_err(dev, "no regulator found\n"); + return -1; + } + + if (enable) { + ret = regulator_enable(ldo); + if (ret) +- dev_err(dev, "%s: fail to enable phy-supply\n", +- __func__); ++ dev_err(dev, "fail to enable phy-supply\n"); + } else { + ret = regulator_disable(ldo); + if (ret) +- dev_err(dev, "%s: fail to disable phy-supply\n", +- __func__); ++ dev_err(dev, "fail to disable phy-supply\n"); + } + + return 0; + } + +-static void *rk_gmac_setup(struct platform_device *pdev) ++static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev, ++ const struct rk_gmac_ops *ops) + { + struct rk_priv_data *bsp_priv; + struct device *dev = &pdev->dev; +@@ -323,6 +461,7 @@ static void *rk_gmac_setup(struct platfo + return ERR_PTR(-ENOMEM); + + bsp_priv->phy_iface = of_get_phy_mode(dev->of_node); ++ bsp_priv->ops = ops; + + bsp_priv->regulator = devm_regulator_get_optional(dev, "phy"); + if (IS_ERR(bsp_priv->regulator)) { +@@ -336,12 +475,11 @@ static void *rk_gmac_setup(struct platfo + + ret = of_property_read_string(dev->of_node, "clock_in_out", &strings); + if (ret) { +- dev_err(dev, "%s: Can not read property: clock_in_out.\n", +- __func__); ++ dev_err(dev, "Can not read property: clock_in_out.\n"); + bsp_priv->clock_input = true; + } else { +- dev_info(dev, "%s: clock input or output? (%s).\n", +- __func__, strings); ++ dev_info(dev, "clock input or output? (%s).\n", ++ strings); + if (!strcmp(strings, "input")) + bsp_priv->clock_input = true; + else +@@ -351,22 +489,22 @@ static void *rk_gmac_setup(struct platfo + ret = of_property_read_u32(dev->of_node, "tx_delay", &value); + if (ret) { + bsp_priv->tx_delay = 0x30; +- dev_err(dev, "%s: Can not read property: tx_delay.", __func__); +- dev_err(dev, "%s: set tx_delay to 0x%x\n", +- __func__, bsp_priv->tx_delay); ++ dev_err(dev, "Can not read property: tx_delay."); ++ dev_err(dev, "set tx_delay to 0x%x\n", ++ bsp_priv->tx_delay); + } else { +- dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value); ++ dev_info(dev, "TX delay(0x%x).\n", value); + bsp_priv->tx_delay = value; + } + + ret = of_property_read_u32(dev->of_node, "rx_delay", &value); + if (ret) { + bsp_priv->rx_delay = 0x10; +- dev_err(dev, "%s: Can not read property: rx_delay.", __func__); +- dev_err(dev, "%s: set rx_delay to 0x%x\n", +- __func__, bsp_priv->rx_delay); ++ dev_err(dev, "Can not read property: rx_delay."); ++ dev_err(dev, "set rx_delay to 0x%x\n", ++ bsp_priv->rx_delay); + } else { +- dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value); ++ dev_info(dev, "RX delay(0x%x).\n", value); + bsp_priv->rx_delay = value; + } + +@@ -376,13 +514,14 @@ static void *rk_gmac_setup(struct platfo + + /*rmii or rgmii*/ + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) { +- dev_info(dev, "%s: init for RGMII\n", __func__); +- set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay); ++ dev_info(dev, "init for RGMII\n"); ++ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay, ++ bsp_priv->rx_delay); + } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) { +- dev_info(dev, "%s: init for RMII\n", __func__); +- set_to_rmii(bsp_priv); ++ dev_info(dev, "init for RMII\n"); ++ bsp_priv->ops->set_to_rmii(bsp_priv); + } else { +- dev_err(dev, "%s: NO interface defined!\n", __func__); ++ dev_err(dev, "NO interface defined!\n"); + } + + gmac_clk_init(bsp_priv); +@@ -420,17 +559,68 @@ static void rk_fix_speed(void *priv, uns + struct device *dev = &bsp_priv->pdev->dev; + + if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) +- set_rgmii_speed(bsp_priv, speed); ++ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed); + else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) +- set_rmii_speed(bsp_priv, speed); ++ bsp_priv->ops->set_rmii_speed(bsp_priv, speed); + else + dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface); + } + +-const struct stmmac_of_data rk3288_gmac_data = { +- .has_gmac = 1, +- .fix_mac_speed = rk_fix_speed, +- .setup = rk_gmac_setup, +- .init = rk_gmac_init, +- .exit = rk_gmac_exit, ++static int rk_gmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ const struct rk_gmac_ops *data; ++ int ret; ++ ++ data = of_device_get_match_data(&pdev->dev); ++ if (!data) { ++ dev_err(&pdev->dev, "no of match data provided\n"); ++ return -EINVAL; ++ } ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ ++ plat_dat->has_gmac = true; ++ plat_dat->init = rk_gmac_init; ++ plat_dat->exit = rk_gmac_exit; ++ plat_dat->fix_mac_speed = rk_fix_speed; ++ ++ plat_dat->bsp_priv = rk_gmac_setup(pdev, data); ++ if (IS_ERR(plat_dat->bsp_priv)) ++ return PTR_ERR(plat_dat->bsp_priv); ++ ++ ret = rk_gmac_init(pdev, plat_dat->bsp_priv); ++ if (ret) ++ return ret; ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++} ++ ++static const struct of_device_id rk_gmac_dwmac_match[] = { ++ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops }, ++ { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops }, ++ { } + }; ++MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); ++ ++static struct platform_driver rk_gmac_dwmac_driver = { ++ .probe = rk_gmac_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = "rk_gmac-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = rk_gmac_dwmac_match, ++ }, ++}; ++module_platform_driver(rk_gmac_dwmac_driver); ++ ++MODULE_AUTHOR("Chen-Zhi (Roger Chen) "); ++MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer"); ++MODULE_LICENSE("GPL"); +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +@@ -175,31 +175,6 @@ static int socfpga_dwmac_setup(struct so + return 0; + } + +-static void *socfpga_dwmac_probe(struct platform_device *pdev) +-{ +- struct device *dev = &pdev->dev; +- int ret; +- struct socfpga_dwmac *dwmac; +- +- dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); +- if (!dwmac) +- return ERR_PTR(-ENOMEM); +- +- ret = socfpga_dwmac_parse_data(dwmac, dev); +- if (ret) { +- dev_err(dev, "Unable to parse OF data\n"); +- return ERR_PTR(ret); +- } +- +- ret = socfpga_dwmac_setup(dwmac); +- if (ret) { +- dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); +- return ERR_PTR(ret); +- } +- +- return dwmac; +-} +- + static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv) + { + struct socfpga_dwmac *dwmac = priv; +@@ -257,9 +232,65 @@ static int socfpga_dwmac_init(struct pla + return ret; + } + +-const struct stmmac_of_data socfpga_gmac_data = { +- .setup = socfpga_dwmac_probe, +- .init = socfpga_dwmac_init, +- .exit = socfpga_dwmac_exit, +- .fix_mac_speed = socfpga_dwmac_fix_mac_speed, ++static int socfpga_dwmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ struct device *dev = &pdev->dev; ++ int ret; ++ struct socfpga_dwmac *dwmac; ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ ++ dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL); ++ if (!dwmac) ++ return -ENOMEM; ++ ++ ret = socfpga_dwmac_parse_data(dwmac, dev); ++ if (ret) { ++ dev_err(dev, "Unable to parse OF data\n"); ++ return ret; ++ } ++ ++ ret = socfpga_dwmac_setup(dwmac); ++ if (ret) { ++ dev_err(dev, "couldn't setup SoC glue (%d)\n", ret); ++ return ret; ++ } ++ ++ plat_dat->bsp_priv = dwmac; ++ plat_dat->init = socfpga_dwmac_init; ++ plat_dat->exit = socfpga_dwmac_exit; ++ plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed; ++ ++ ret = socfpga_dwmac_init(pdev, plat_dat->bsp_priv); ++ if (ret) ++ return ret; ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++} ++ ++static const struct of_device_id socfpga_dwmac_match[] = { ++ { .compatible = "altr,socfpga-stmmac" }, ++ { } + }; ++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 = &stmmac_pltfr_pm_ops, ++ .of_match_table = socfpga_dwmac_match, ++ }, ++}; ++module_platform_driver(socfpga_dwmac_driver); ++ ++MODULE_LICENSE("GPL v2"); +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +@@ -17,9 +17,11 @@ + #include + #include + #include ++#include + #include + #include + #include ++#include + #include + + #include "stmmac_platform.h" +@@ -127,6 +129,11 @@ struct sti_dwmac { + struct device *dev; + struct regmap *regmap; + u32 speed; ++ void (*fix_retime_src)(void *priv, unsigned int speed); ++}; ++ ++struct sti_dwmac_of_data { ++ void (*fix_retime_src)(void *priv, unsigned int speed); + }; + + static u32 phy_intf_sels[] = { +@@ -221,8 +228,9 @@ static void stid127_fix_retime_src(void + regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val); + } + +-static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac) ++static int sti_dwmac_init(struct platform_device *pdev, void *priv) + { ++ struct sti_dwmac *dwmac = priv; + struct regmap *regmap = dwmac->regmap; + int iface = dwmac->interface; + struct device *dev = dwmac->dev; +@@ -240,28 +248,8 @@ static void sti_dwmac_ctrl_init(struct s + + val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; + regmap_update_bits(regmap, reg, ENMII_MASK, val); +-} +- +-static int stix4xx_init(struct platform_device *pdev, void *priv) +-{ +- struct sti_dwmac *dwmac = priv; +- u32 spd = dwmac->speed; + +- sti_dwmac_ctrl_init(dwmac); +- +- stih4xx_fix_retime_src(priv, spd); +- +- return 0; +-} +- +-static int stid127_init(struct platform_device *pdev, void *priv) +-{ +- struct sti_dwmac *dwmac = priv; +- u32 spd = dwmac->speed; +- +- sti_dwmac_ctrl_init(dwmac); +- +- stid127_fix_retime_src(priv, spd); ++ dwmac->fix_retime_src(priv, dwmac->speed); + + return 0; + } +@@ -333,34 +321,80 @@ static int sti_dwmac_parse_data(struct s + return 0; + } + +-static void *sti_dwmac_setup(struct platform_device *pdev) ++static int sti_dwmac_probe(struct platform_device *pdev) + { ++ struct plat_stmmacenet_data *plat_dat; ++ const struct sti_dwmac_of_data *data; ++ struct stmmac_resources stmmac_res; + struct sti_dwmac *dwmac; + int ret; + ++ data = of_device_get_match_data(&pdev->dev); ++ if (!data) { ++ dev_err(&pdev->dev, "No OF match data provided\n"); ++ return -EINVAL; ++ } ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + ret = sti_dwmac_parse_data(dwmac, pdev); + if (ret) { + dev_err(&pdev->dev, "Unable to parse OF data\n"); +- return ERR_PTR(ret); ++ return ret; + } + +- return dwmac; ++ dwmac->fix_retime_src = data->fix_retime_src; ++ ++ plat_dat->bsp_priv = dwmac; ++ plat_dat->init = sti_dwmac_init; ++ plat_dat->exit = sti_dwmac_exit; ++ plat_dat->fix_mac_speed = data->fix_retime_src; ++ ++ ret = sti_dwmac_init(pdev, plat_dat->bsp_priv); ++ if (ret) ++ return ret; ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + } + +-const struct stmmac_of_data stih4xx_dwmac_data = { +- .fix_mac_speed = stih4xx_fix_retime_src, +- .setup = sti_dwmac_setup, +- .init = stix4xx_init, +- .exit = sti_dwmac_exit, ++static const struct sti_dwmac_of_data stih4xx_dwmac_data = { ++ .fix_retime_src = stih4xx_fix_retime_src, ++}; ++ ++static const struct sti_dwmac_of_data stid127_dwmac_data = { ++ .fix_retime_src = stid127_fix_retime_src, + }; + +-const struct stmmac_of_data stid127_dwmac_data = { +- .fix_mac_speed = stid127_fix_retime_src, +- .setup = sti_dwmac_setup, +- .init = stid127_init, +- .exit = sti_dwmac_exit, ++static const struct of_device_id sti_dwmac_match[] = { ++ { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, ++ { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data}, ++ { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data}, ++ { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data}, ++ { } + }; ++MODULE_DEVICE_TABLE(of, sti_dwmac_match); ++ ++static struct platform_driver sti_dwmac_driver = { ++ .probe = sti_dwmac_probe, ++ .remove = stmmac_pltfr_remove, ++ .driver = { ++ .name = "sti-dwmac", ++ .pm = &stmmac_pltfr_pm_ops, ++ .of_match_table = sti_dwmac_match, ++ }, ++}; ++module_platform_driver(sti_dwmac_driver); ++ ++MODULE_AUTHOR("Srinivas Kandagatla "); ++MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer"); ++MODULE_LICENSE("GPL"); +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +@@ -18,7 +18,9 @@ + + #include + #include ++#include + #include ++#include + #include + #include + +@@ -31,35 +33,6 @@ struct sunxi_priv_data { + struct regulator *regulator; + }; + +-static void *sun7i_gmac_setup(struct platform_device *pdev) +-{ +- struct sunxi_priv_data *gmac; +- struct device *dev = &pdev->dev; +- +- gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); +- if (!gmac) +- return ERR_PTR(-ENOMEM); +- +- gmac->interface = of_get_phy_mode(dev->of_node); +- +- gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); +- if (IS_ERR(gmac->tx_clk)) { +- dev_err(dev, "could not get tx clock\n"); +- return gmac->tx_clk; +- } +- +- /* Optional regulator for PHY */ +- gmac->regulator = devm_regulator_get_optional(dev, "phy"); +- if (IS_ERR(gmac->regulator)) { +- if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) +- return ERR_PTR(-EPROBE_DEFER); +- dev_info(dev, "no regulator found\n"); +- gmac->regulator = NULL; +- } +- +- return gmac; +-} +- + #define SUN7I_GMAC_GMII_RGMII_RATE 125000000 + #define SUN7I_GMAC_MII_RATE 25000000 + +@@ -130,13 +103,76 @@ static void sun7i_fix_speed(void *priv, + } + } + +-/* of_data specifying hardware features and callbacks. +- * hardware features were copied from Allwinner drivers. */ +-const struct stmmac_of_data sun7i_gmac_data = { +- .has_gmac = 1, +- .tx_coe = 1, +- .fix_mac_speed = sun7i_fix_speed, +- .setup = sun7i_gmac_setup, +- .init = sun7i_gmac_init, +- .exit = sun7i_gmac_exit, ++static int sun7i_gmac_probe(struct platform_device *pdev) ++{ ++ struct plat_stmmacenet_data *plat_dat; ++ struct stmmac_resources stmmac_res; ++ struct sunxi_priv_data *gmac; ++ struct device *dev = &pdev->dev; ++ int ret; ++ ++ ret = stmmac_get_platform_resources(pdev, &stmmac_res); ++ if (ret) ++ return ret; ++ ++ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); ++ if (IS_ERR(plat_dat)) ++ return PTR_ERR(plat_dat); ++ ++ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); ++ if (!gmac) ++ return -ENOMEM; ++ ++ gmac->interface = of_get_phy_mode(dev->of_node); ++ ++ gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx"); ++ if (IS_ERR(gmac->tx_clk)) { ++ dev_err(dev, "could not get tx clock\n"); ++ return PTR_ERR(gmac->tx_clk); ++ } ++ ++ /* Optional regulator for PHY */ ++ gmac->regulator = devm_regulator_get_optional(dev, "phy"); ++ if (IS_ERR(gmac->regulator)) { ++ if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER) ++ return -EPROBE_DEFER; ++ dev_info(dev, "no regulator found\n"); ++ gmac->regulator = NULL; ++ } ++ ++ /* 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->bsp_priv = gmac; ++ plat_dat->init = sun7i_gmac_init; ++ plat_dat->exit = sun7i_gmac_exit; ++ plat_dat->fix_mac_speed = sun7i_fix_speed; ++ ++ ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv); ++ if (ret) ++ return ret; ++ ++ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); ++} ++ ++static const struct of_device_id sun7i_dwmac_match[] = { ++ { .compatible = "allwinner,sun7i-a20-gmac" }, ++ { } + }; ++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, ++ .of_match_table = sun7i_dwmac_match, ++ }, ++}; ++module_platform_driver(sun7i_dwmac_driver); ++ ++MODULE_AUTHOR("Chen-Yu Tsai "); ++MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer"); ++MODULE_LICENSE("GPL"); +--- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c ++++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +@@ -73,7 +73,7 @@ + #define MMC_RX_OCTETCOUNT_G 0x00000188 + #define MMC_RX_BROADCASTFRAME_G 0x0000018c + #define MMC_RX_MULTICASTFRAME_G 0x00000190 +-#define MMC_RX_CRC_ERRROR 0x00000194 ++#define MMC_RX_CRC_ERROR 0x00000194 + #define MMC_RX_ALIGN_ERROR 0x00000198 + #define MMC_RX_RUN_ERROR 0x0000019C + #define MMC_RX_JABBER_ERROR 0x000001A0 +@@ -196,7 +196,7 @@ void dwmac_mmc_read(void __iomem *ioaddr + mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G); + mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G); + mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G); +- mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERRROR); ++ mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERROR); + mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR); + mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR); + mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR); +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +@@ -34,6 +34,14 @@ + #include + #include + ++struct stmmac_resources { ++ void __iomem *addr; ++ const char *mac; ++ int wol_irq; ++ int lpi_irq; ++ int irq; ++}; ++ + struct stmmac_tx_info { + dma_addr_t buf; + bool map_as_page; +@@ -135,9 +143,9 @@ void stmmac_ptp_unregister(struct stmmac + int stmmac_resume(struct net_device *ndev); + int stmmac_suspend(struct net_device *ndev); + int stmmac_dvr_remove(struct net_device *ndev); +-struct stmmac_priv *stmmac_dvr_probe(struct device *device, +- struct plat_stmmacenet_data *plat_dat, +- void __iomem *addr); ++int stmmac_dvr_probe(struct device *device, ++ struct plat_stmmacenet_data *plat_dat, ++ struct stmmac_resources *res); + void stmmac_disable_eee_mode(struct stmmac_priv *priv); + bool stmmac_eee_init(struct stmmac_priv *priv); + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -52,6 +52,7 @@ + #include "stmmac_ptp.h" + #include "stmmac.h" + #include ++#include + + #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) + +@@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_de + priv->speed = 0; + priv->oldduplex = -1; + +- if (priv->plat->phy_bus_name) +- snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", +- priv->plat->phy_bus_name, priv->plat->bus_id); +- else +- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", +- priv->plat->bus_id); ++ if (priv->plat->phy_node) { ++ phydev = of_phy_connect(dev, priv->plat->phy_node, ++ &stmmac_adjust_link, 0, interface); ++ } else { ++ if (priv->plat->phy_bus_name) ++ snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", ++ priv->plat->phy_bus_name, priv->plat->bus_id); ++ else ++ snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", ++ priv->plat->bus_id); + +- snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, +- priv->plat->phy_addr); +- pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt); ++ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, ++ priv->plat->phy_addr); ++ pr_debug("stmmac_init_phy: trying to attach to %s\n", ++ phy_id_fmt); + +- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface); ++ phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, ++ interface); ++ } + + if (IS_ERR_OR_NULL(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); +@@ -851,7 +859,7 @@ static int stmmac_init_phy(struct net_de + * device as well. + * Note: phydev->phy_id is the result of reading the UID PHY registers. + */ +- if (phydev->phy_id == 0) { ++ if (!priv->plat->phy_node && phydev->phy_id == 0) { + phy_disconnect(phydev); + return -ENODEV; + } +@@ -978,13 +986,11 @@ static int stmmac_init_rx_buffers(struct + { + struct sk_buff *skb; + +- skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN, +- flags); ++ skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags); + if (!skb) { + pr_err("%s: Rx init fails; skb is NULL\n", __func__); + return -ENOMEM; + } +- skb_reserve(skb, NET_IP_ALIGN); + priv->rx_skbuff[i] = skb; + priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, + priv->dma_buf_sz, +@@ -2803,16 +2809,15 @@ static int stmmac_hw_init(struct stmmac_ + * stmmac_dvr_probe + * @device: device pointer + * @plat_dat: platform data pointer +- * @addr: iobase memory address ++ * @res: stmmac resource pointer + * Description: this is the main probe function used to + * call the alloc_etherdev, allocate the priv structure. + * Return: +- * on success the new private structure is returned, otherwise the error +- * pointer. ++ * returns 0 on success, otherwise errno. + */ +-struct stmmac_priv *stmmac_dvr_probe(struct device *device, +- struct plat_stmmacenet_data *plat_dat, +- void __iomem *addr) ++int stmmac_dvr_probe(struct device *device, ++ struct plat_stmmacenet_data *plat_dat, ++ struct stmmac_resources *res) + { + int ret = 0; + struct net_device *ndev = NULL; +@@ -2820,7 +2825,7 @@ struct stmmac_priv *stmmac_dvr_probe(str + + ndev = alloc_etherdev(sizeof(struct stmmac_priv)); + if (!ndev) +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + + SET_NETDEV_DEV(ndev, device); + +@@ -2831,8 +2836,17 @@ struct stmmac_priv *stmmac_dvr_probe(str + stmmac_set_ethtool_ops(ndev); + priv->pause = pause; + priv->plat = plat_dat; +- priv->ioaddr = addr; +- priv->dev->base_addr = (unsigned long)addr; ++ priv->ioaddr = res->addr; ++ priv->dev->base_addr = (unsigned long)res->addr; ++ ++ priv->dev->irq = res->irq; ++ priv->wol_irq = res->wol_irq; ++ priv->lpi_irq = res->lpi_irq; ++ ++ if (res->mac) ++ memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN); ++ ++ dev_set_drvdata(device, priv->dev); + + /* Verify driver arguments */ + stmmac_verify_args(); +@@ -2947,7 +2961,7 @@ struct stmmac_priv *stmmac_dvr_probe(str + } + } + +- return priv; ++ return 0; + + error_mdio_register: + unregister_netdev(ndev); +@@ -2960,7 +2974,7 @@ error_pclk_get: + error_clk_get: + free_netdev(ndev); + +- return ERR_PTR(ret); ++ return ret; + } + EXPORT_SYMBOL_GPL(stmmac_dvr_probe); + +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +@@ -161,11 +161,16 @@ int stmmac_mdio_reset(struct mii_bus *bu + + if (!gpio_request(reset_gpio, "mdio-reset")) { + gpio_direction_output(reset_gpio, active_low ? 1 : 0); +- udelay(data->delays[0]); ++ if (data->delays[0]) ++ msleep(DIV_ROUND_UP(data->delays[0], 1000)); ++ + gpio_set_value(reset_gpio, active_low ? 0 : 1); +- udelay(data->delays[1]); ++ if (data->delays[1]) ++ msleep(DIV_ROUND_UP(data->delays[1], 1000)); ++ + gpio_set_value(reset_gpio, active_low ? 1 : 0); +- udelay(data->delays[2]); ++ if (data->delays[2]) ++ msleep(DIV_ROUND_UP(data->delays[2], 1000)); + } + } + #endif +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +@@ -163,7 +163,7 @@ static int stmmac_pci_probe(struct pci_d + { + struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data; + struct plat_stmmacenet_data *plat; +- struct stmmac_priv *priv; ++ struct stmmac_resources res; + int i; + int ret; + +@@ -214,19 +214,12 @@ static int stmmac_pci_probe(struct pci_d + + pci_enable_msi(pdev); + +- priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]); +- if (IS_ERR(priv)) { +- dev_err(&pdev->dev, "%s: main driver probe failed\n", __func__); +- return PTR_ERR(priv); +- } +- priv->dev->irq = pdev->irq; +- priv->wol_irq = pdev->irq; +- +- pci_set_drvdata(pdev, priv->dev); +- +- dev_dbg(&pdev->dev, "STMMAC PCI driver registration completed\n"); ++ memset(&res, 0, sizeof(res)); ++ res.addr = pcim_iomap_table(pdev)[i]; ++ res.wol_irq = pdev->irq; ++ res.irq = pdev->irq; + +- return 0; ++ return stmmac_dvr_probe(&pdev->dev, plat, &res); + } + + /** +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -28,29 +28,11 @@ + #include + #include + #include ++#include + + #include "stmmac.h" + #include "stmmac_platform.h" + +-static const struct of_device_id stmmac_dt_ids[] = { +- /* SoC specific glue layers should come before generic bindings */ +- { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data}, +- { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data}, +- { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, +- { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, +- { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data}, +- { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data}, +- { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data}, +- { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data }, +- { .compatible = "st,spear600-gmac"}, +- { .compatible = "snps,dwmac-3.610"}, +- { .compatible = "snps,dwmac-3.70a"}, +- { .compatible = "snps,dwmac-3.710"}, +- { .compatible = "snps,dwmac"}, +- { /* sentinel */ } +-}; +-MODULE_DEVICE_TABLE(of, stmmac_dt_ids); +- + #ifdef CONFIG_OF + + /** +@@ -122,37 +104,16 @@ static int dwmac1000_validate_ucast_entr + * this function is to read the driver parameters from device-tree and + * set some private fields that will be used by the main at runtime. + */ +-static int stmmac_probe_config_dt(struct platform_device *pdev, +- struct plat_stmmacenet_data *plat, +- const char **mac) ++struct plat_stmmacenet_data * ++stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) + { + struct device_node *np = pdev->dev.of_node; ++ struct plat_stmmacenet_data *plat; + struct stmmac_dma_cfg *dma_cfg; +- const struct of_device_id *device; +- +- if (!np) +- return -ENODEV; + +- device = of_match_device(stmmac_dt_ids, &pdev->dev); +- if (!device) +- return -ENODEV; +- +- if (device->data) { +- const struct stmmac_of_data *data = device->data; +- plat->has_gmac = data->has_gmac; +- plat->enh_desc = data->enh_desc; +- plat->tx_coe = data->tx_coe; +- plat->rx_coe = data->rx_coe; +- plat->bugged_jumbo = data->bugged_jumbo; +- plat->pmt = data->pmt; +- plat->riwt_off = data->riwt_off; +- plat->fix_mac_speed = data->fix_mac_speed; +- plat->bus_setup = data->bus_setup; +- plat->setup = data->setup; +- plat->free = data->free; +- plat->init = data->init; +- plat->exit = data->exit; +- } ++ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); ++ if (!plat) ++ return ERR_PTR(-ENOMEM); + + *mac = of_get_mac_address(np); + plat->interface = of_get_phy_mode(np); +@@ -168,13 +129,24 @@ static int stmmac_probe_config_dt(struct + /* Default to phy auto-detection */ + plat->phy_addr = -1; + ++ /* If we find a phy-handle property, use it as the PHY */ ++ plat->phy_node = of_parse_phandle(np, "phy-handle", 0); ++ ++ /* If phy-handle is not specified, check if we have a fixed-phy */ ++ if (!plat->phy_node && of_phy_is_fixed_link(np)) { ++ if ((of_phy_register_fixed_link(np) < 0)) ++ return ERR_PTR(-ENODEV); ++ ++ plat->phy_node = of_node_get(np); ++ } ++ + /* "snps,phy-addr" is not a standard property. Mark it as deprecated + * and warn of its use. Remove this when phy node support is added. + */ + if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0) + dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); + +- if (plat->phy_bus_name) ++ if (plat->phy_node || plat->phy_bus_name) + plat->mdio_bus_data = NULL; + else + plat->mdio_bus_data = +@@ -194,6 +166,12 @@ static int stmmac_probe_config_dt(struct + */ + 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 +@@ -232,8 +210,10 @@ static int stmmac_probe_config_dt(struct + if (of_find_property(np, "snps,pbl", NULL)) { + dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), + GFP_KERNEL); +- if (!dma_cfg) +- return -ENOMEM; ++ if (!dma_cfg) { ++ of_node_put(np); ++ return ERR_PTR(-ENOMEM); ++ } + plat->dma_cfg = dma_cfg; + of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); + dma_cfg->fixed_burst = +@@ -250,45 +230,34 @@ static int stmmac_probe_config_dt(struct + pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set."); + } + +- return 0; ++ return plat; + } + #else +-static int stmmac_probe_config_dt(struct platform_device *pdev, +- struct plat_stmmacenet_data *plat, +- const char **mac) ++struct plat_stmmacenet_data * ++stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) + { +- return -ENOSYS; ++ return ERR_PTR(-ENOSYS); + } + #endif /* CONFIG_OF */ ++EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); + +-/** +- * stmmac_pltfr_probe - platform driver probe. +- * @pdev: platform device pointer +- * Description: platform_device probe function. It is to allocate +- * the necessary platform resources, invoke custom helper (if required) and +- * invoke the main probe function. +- */ +-static int stmmac_pltfr_probe(struct platform_device *pdev) ++int stmmac_get_platform_resources(struct platform_device *pdev, ++ struct stmmac_resources *stmmac_res) + { +- int ret = 0; + struct resource *res; +- struct device *dev = &pdev->dev; +- void __iomem *addr = NULL; +- struct stmmac_priv *priv = NULL; +- struct plat_stmmacenet_data *plat_dat = NULL; +- const char *mac = NULL; +- int irq, wol_irq, lpi_irq; ++ ++ memset(stmmac_res, 0, sizeof(*stmmac_res)); + + /* Get IRQ information early to have an ability to ask for deferred + * probe if needed before we went too far with resource allocation. + */ +- irq = platform_get_irq_byname(pdev, "macirq"); +- if (irq < 0) { +- if (irq != -EPROBE_DEFER) { +- dev_err(dev, ++ stmmac_res->irq = platform_get_irq_byname(pdev, "macirq"); ++ if (stmmac_res->irq < 0) { ++ if (stmmac_res->irq != -EPROBE_DEFER) { ++ dev_err(&pdev->dev, + "MAC IRQ configuration information not found\n"); + } +- return irq; ++ return stmmac_res->irq; + } + + /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq +@@ -298,82 +267,23 @@ static int stmmac_pltfr_probe(struct pla + * In case the wake up interrupt is not passed from the platform + * so the driver will continue to use the mac irq (ndev->irq) + */ +- wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); +- if (wol_irq < 0) { +- if (wol_irq == -EPROBE_DEFER) ++ stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); ++ if (stmmac_res->wol_irq < 0) { ++ if (stmmac_res->wol_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; +- wol_irq = irq; ++ stmmac_res->wol_irq = stmmac_res->irq; + } + +- lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); +- if (lpi_irq == -EPROBE_DEFER) ++ stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); ++ if (stmmac_res->lpi_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +- addr = devm_ioremap_resource(dev, res); +- if (IS_ERR(addr)) +- return PTR_ERR(addr); +- +- plat_dat = dev_get_platdata(&pdev->dev); +- +- if (!plat_dat) +- plat_dat = devm_kzalloc(&pdev->dev, +- sizeof(struct plat_stmmacenet_data), +- GFP_KERNEL); +- if (!plat_dat) { +- pr_err("%s: ERROR: no memory", __func__); +- return -ENOMEM; +- } +- +- /* Set default value for multicast hash bins */ +- plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; ++ stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res); + +- /* Set default value for unicast filter entries */ +- plat_dat->unicast_filter_entries = 1; +- +- if (pdev->dev.of_node) { +- ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); +- if (ret) { +- pr_err("%s: main dt probe failed", __func__); +- return ret; +- } +- } +- +- /* Custom setup (if needed) */ +- if (plat_dat->setup) { +- plat_dat->bsp_priv = plat_dat->setup(pdev); +- if (IS_ERR(plat_dat->bsp_priv)) +- return PTR_ERR(plat_dat->bsp_priv); +- } +- +- /* Custom initialisation (if needed)*/ +- if (plat_dat->init) { +- ret = plat_dat->init(pdev, plat_dat->bsp_priv); +- if (unlikely(ret)) +- return ret; +- } +- +- priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr); +- if (IS_ERR(priv)) { +- pr_err("%s: main driver probe failed", __func__); +- return PTR_ERR(priv); +- } +- +- /* Copy IRQ values to priv structure which is now avaialble */ +- priv->dev->irq = irq; +- priv->wol_irq = wol_irq; +- priv->lpi_irq = lpi_irq; +- +- /* Get MAC address if available (DT) */ +- if (mac) +- memcpy(priv->dev->dev_addr, mac, ETH_ALEN); +- +- platform_set_drvdata(pdev, priv->dev); +- +- pr_debug("STMMAC platform driver registration completed"); +- +- return 0; ++ return PTR_ERR_OR_ZERO(stmmac_res->addr); + } ++EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); + + /** + * stmmac_pltfr_remove +@@ -381,7 +291,7 @@ static int stmmac_pltfr_probe(struct pla + * Description: this function calls the main to free the net resources + * and calls the platforms hook and release the resources (e.g. mem). + */ +-static int stmmac_pltfr_remove(struct platform_device *pdev) ++int stmmac_pltfr_remove(struct platform_device *pdev) + { + struct net_device *ndev = platform_get_drvdata(pdev); + struct stmmac_priv *priv = netdev_priv(ndev); +@@ -390,11 +300,9 @@ static int stmmac_pltfr_remove(struct pl + if (priv->plat->exit) + priv->plat->exit(pdev, priv->plat->bsp_priv); + +- if (priv->plat->free) +- priv->plat->free(pdev, priv->plat->bsp_priv); +- + return ret; + } ++EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); + + #ifdef CONFIG_PM_SLEEP + /** +@@ -438,21 +346,10 @@ static int stmmac_pltfr_resume(struct de + } + #endif /* CONFIG_PM_SLEEP */ + +-static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, +- stmmac_pltfr_suspend, stmmac_pltfr_resume); +- +-static struct platform_driver stmmac_pltfr_driver = { +- .probe = stmmac_pltfr_probe, +- .remove = stmmac_pltfr_remove, +- .driver = { +- .name = STMMAC_RESOURCE_NAME, +- .pm = &stmmac_pltfr_pm_ops, +- .of_match_table = of_match_ptr(stmmac_dt_ids), +- }, +-}; +- +-module_platform_driver(stmmac_pltfr_driver); ++SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend, ++ stmmac_pltfr_resume); ++EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops); + +-MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver"); ++MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support"); + MODULE_AUTHOR("Giuseppe Cavallaro "); + MODULE_LICENSE("GPL"); +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +@@ -19,11 +19,15 @@ + #ifndef __STMMAC_PLATFORM_H__ + #define __STMMAC_PLATFORM_H__ + +-extern const struct stmmac_of_data meson6_dwmac_data; +-extern const struct stmmac_of_data sun7i_gmac_data; +-extern const struct stmmac_of_data stih4xx_dwmac_data; +-extern const struct stmmac_of_data stid127_dwmac_data; +-extern const struct stmmac_of_data socfpga_gmac_data; +-extern const struct stmmac_of_data rk3288_gmac_data; ++#include "stmmac.h" ++ ++struct plat_stmmacenet_data * ++stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); ++ ++int stmmac_get_platform_resources(struct platform_device *pdev, ++ struct stmmac_resources *stmmac_res); ++ ++int stmmac_pltfr_remove(struct platform_device *pdev); ++extern const struct dev_pm_ops stmmac_pltfr_pm_ops; + + #endif /* __STMMAC_PLATFORM_H__ */ +--- a/include/linux/stmmac.h ++++ b/include/linux/stmmac.h +@@ -99,6 +99,7 @@ struct plat_stmmacenet_data { + int phy_addr; + int interface; + struct stmmac_mdio_bus_data *mdio_bus_data; ++ struct device_node *phy_node; + struct stmmac_dma_cfg *dma_cfg; + int clk_csr; + int has_gmac; +@@ -118,30 +119,8 @@ struct plat_stmmacenet_data { + int rx_fifo_size; + void (*fix_mac_speed)(void *priv, unsigned int speed); + void (*bus_setup)(void __iomem *ioaddr); +- void *(*setup)(struct platform_device *pdev); +- void (*free)(struct platform_device *pdev, void *priv); + int (*init)(struct platform_device *pdev, void *priv); + void (*exit)(struct platform_device *pdev, void *priv); +- void *custom_cfg; +- void *custom_data; + void *bsp_priv; + }; +- +-/* of_data for SoC glue layer device tree bindings */ +- +-struct stmmac_of_data { +- int has_gmac; +- int enh_desc; +- int tx_coe; +- int rx_coe; +- int bugged_jumbo; +- int pmt; +- int riwt_off; +- void (*fix_mac_speed)(void *priv, unsigned int speed); +- void (*bus_setup)(void __iomem *ioaddr); +- void *(*setup)(struct platform_device *pdev); +- void (*free)(struct platform_device *pdev, void *priv); +- int (*init)(struct platform_device *pdev, void *priv); +- void (*exit)(struct platform_device *pdev, void *priv); +-}; + #endif -- cgit v1.2.3