diff options
Diffstat (limited to 'target/linux/ipq806x/patches-4.1')
7 files changed, 2371 insertions, 713 deletions
diff --git a/target/linux/ipq806x/patches-4.1/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch b/target/linux/ipq806x/patches-4.1/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch deleted file mode 100644 index 5c29887248..0000000000 --- a/target/linux/ipq806x/patches-4.1/701-stmmac-add-phy-handle-support-to-the-platform-layer.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 4f09499bc1d9bb095caccbcd73ff951ee631e521 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Fri, 8 May 2015 15:42:40 -0700 -Subject: [PATCH 1/8] stmmac: add phy-handle support to the platform layer - -On stmmac driver, PHY specification in device-tree was done using the -non-standard property "snps,phy-addr". Specifying a PHY on a different -MDIO bus that the one within the stmmac controller doesn't seem to be -possible when device-tree is used. - -This change adds support for the phy-handle property, as specified in -Documentation/devicetree/bindings/net/ethernet.txt. - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> ---- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 28 ++++++++++++++-------- - .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 6 ++++- - include/linux/stmmac.h | 1 + - 3 files changed, 24 insertions(+), 11 deletions(-) - ---- 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 <linux/reset.h> -+#include <linux/of_mdio.h> - - #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); -- -- 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); -+ 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); - -- 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); ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -28,6 +28,7 @@ - #include <linux/of.h> - #include <linux/of_net.h> - #include <linux/of_device.h> -+#include <linux/of_mdio.h> - - #include "stmmac.h" - #include "stmmac_platform.h" -@@ -168,13 +169,16 @@ 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); -+ - /* "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 = ---- 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; 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 +- <http://www.tldp.org/docs.html#howto>. ++ 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 <manabian@gmail.com> ++ * ++ * 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 <linux/module.h> ++#include <linux/of.h> ++#include <linux/platform_device.h> ++ ++#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 <linux/device.h> ++#include <linux/platform_device.h> ++#include <linux/phy.h> ++#include <linux/regmap.h> ++#include <linux/clk.h> ++#include <linux/reset.h> ++#include <linux/of_net.h> ++#include <linux/mfd/syscon.h> ++#include <linux/stmmac.h> ++#include <linux/of_mdio.h> ++#include <linux/module.h> ++ ++#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 <mathieu@codeaurora.org>"); ++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 <manabian@gmail.com> ++ * ++ * 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 <linux/mfd/syscon.h> ++#include <linux/module.h> ++#include <linux/of.h> ++#include <linux/of_net.h> ++#include <linux/phy.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/stmmac.h> ++ ++#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 <manabian@gmail.com>"); ++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 <linux/ethtool.h> + #include <linux/io.h> + #include <linux/ioport.h> ++#include <linux/module.h> + #include <linux/platform_device.h> + #include <linux/stmmac.h> + +@@ -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 <b.galvani@gmail.com>"); ++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 <linux/phy.h> + #include <linux/of_net.h> + #include <linux/gpio.h> ++#include <linux/module.h> + #include <linux/of_gpio.h> + #include <linux/of_device.h> ++#include <linux/platform_device.h> + #include <linux/regulator/consumer.h> + #include <linux/delay.h> + #include <linux/mfd/syscon.h> + #include <linux/regmap.h> + ++#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) <roger.chen@rock-chips.com>"); ++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 <linux/stmmac.h> + #include <linux/phy.h> + #include <linux/mfd/syscon.h> ++#include <linux/module.h> + #include <linux/regmap.h> + #include <linux/clk.h> + #include <linux/of.h> ++#include <linux/of_device.h> + #include <linux/of_net.h> + + #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 <srinivas.kandagatla@st.com>"); ++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 <linux/stmmac.h> + #include <linux/clk.h> ++#include <linux/module.h> + #include <linux/phy.h> ++#include <linux/platform_device.h> + #include <linux/of_net.h> + #include <linux/regulator/consumer.h> + +@@ -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 <wens@csie.org>"); ++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 <linux/ptp_clock_kernel.h> + #include <linux/reset.h> + ++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 <linux/reset.h> ++#include <linux/of_mdio.h> + + #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 <linux/of.h> + #include <linux/of_net.h> + #include <linux/of_device.h> ++#include <linux/of_mdio.h> + + #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 <peppe.cavallaro@st.com>"); + 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 diff --git a/target/linux/ipq806x/patches-4.1/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch b/target/linux/ipq806x/patches-4.1/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch deleted file mode 100644 index 37f1002131..0000000000 --- a/target/linux/ipq806x/patches-4.1/702-stmmac-move-error-path-at-the-end-of-stmmac_probe_co.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 0149d275415cd1b2382ce94e5eb32641590097d0 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Fri, 8 May 2015 15:57:12 -0700 -Subject: [PATCH 2/8] stmmac: move error path at the end of - stmmac_probe_config_dt() - -We will want to do additional clean-up on certain errors. Therefore, -this change moves the error path at the end of the function for better -code readability. - -This patch doesn't change anything functionally. - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> ---- - .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 22 ++++++++++++++++------ - 1 file changed, 16 insertions(+), 6 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -130,13 +130,18 @@ static int stmmac_probe_config_dt(struct - struct device_node *np = pdev->dev.of_node; - struct stmmac_dma_cfg *dma_cfg; - const struct of_device_id *device; -+ int ret; - -- if (!np) -- return -ENODEV; -+ if (!np) { -+ ret = -ENODEV; -+ goto err; -+ } - - device = of_match_device(stmmac_dt_ids, &pdev->dev); -- if (!device) -- return -ENODEV; -+ if (!device) { -+ ret = -ENODEV; -+ goto err; -+ } - - if (device->data) { - const struct stmmac_of_data *data = device->data; -@@ -236,8 +241,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) { -+ ret = -ENOMEM; -+ goto err; -+ } - plat->dma_cfg = dma_cfg; - of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); - dma_cfg->fixed_burst = -@@ -255,6 +262,9 @@ static int stmmac_probe_config_dt(struct - } - - return 0; -+ -+err: -+ return ret; - } - #else - static int stmmac_probe_config_dt(struct platform_device *pdev, diff --git a/target/linux/ipq806x/patches-4.1/703-stmmac-add-fixed-link-device-tree-support.patch b/target/linux/ipq806x/patches-4.1/703-stmmac-add-fixed-link-device-tree-support.patch deleted file mode 100644 index f2305ac5aa..0000000000 --- a/target/linux/ipq806x/patches-4.1/703-stmmac-add-fixed-link-device-tree-support.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 3a95f75867be562cb919ff23a738f70357188fbd Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Fri, 8 May 2015 16:02:03 -0700 -Subject: [PATCH 3/8] stmmac: add fixed-link device-tree support - -In case DT is used, this change adds the ability to the stmmac driver to -detect a fixed-link PHY, instanciate it, and use it during -phy_connect(). - -Fixed link PHYs DT usage is described in: -Documentation/devicetree/bindings/net/fixed-link.txt - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> ---- - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 2 +- - drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 12 +++++++++++- - 2 files changed, 12 insertions(+), 2 deletions(-) - ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -859,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; - } ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -177,6 +177,14 @@ static int stmmac_probe_config_dt(struct - /* 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 -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. - */ -@@ -243,7 +251,7 @@ static int stmmac_probe_config_dt(struct - GFP_KERNEL); - if (!dma_cfg) { - ret = -ENOMEM; -- goto err; -+ goto err2; - } - plat->dma_cfg = dma_cfg; - of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); -@@ -263,6 +271,8 @@ static int stmmac_probe_config_dt(struct - - return 0; - -+err2: -+ of_node_put(np); - err: - return ret; - } diff --git a/target/linux/ipq806x/patches-4.1/704-stmmac-add-ipq806x-glue-layer.patch b/target/linux/ipq806x/patches-4.1/704-stmmac-add-ipq806x-glue-layer.patch deleted file mode 100644 index 7fd72be5a8..0000000000 --- a/target/linux/ipq806x/patches-4.1/704-stmmac-add-ipq806x-glue-layer.patch +++ /dev/null @@ -1,407 +0,0 @@ -From 69fb970ad3fe05af7cb99ea78230c69c7ca0d03b Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Fri, 8 May 2015 16:10:22 -0700 -Subject: [PATCH 4/8] stmmac: add ipq806x glue layer - -The ethernet controller available in IPQ806x is a Synopsys DesignWare -Gigabit MAC IP core, already supported by the stmmac driver. - -This glue layer implements some platform specific settings required to -get the controller working on an IPQ806x based platform. - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> ---- - drivers/net/ethernet/stmicro/stmmac/Kconfig | 1 + - drivers/net/ethernet/stmicro/stmmac/Makefile | 2 +- - drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c | 324 +++++++++++++++++++++ - .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 1 + - .../net/ethernet/stmicro/stmmac/stmmac_platform.h | 1 + - 5 files changed, 328 insertions(+), 1 deletion(-) - create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-ipq.c - ---- 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. ---- a/drivers/net/ethernet/stmicro/stmmac/Makefile -+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile -@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethto - - 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 -+ dwmac-sti.o dwmac-socfpga.o dwmac-rk.o dwmac-ipq806x.o - - obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o - stmmac-pci-objs:= stmmac_pci.o ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -43,6 +43,7 @@ static const struct of_device_id stmmac_ - { .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 = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data }, - { .compatible = "st,spear600-gmac"}, - { .compatible = "snps,dwmac-3.610"}, - { .compatible = "snps,dwmac-3.70a"}, ---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h -+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h -@@ -25,5 +25,6 @@ extern const struct stmmac_of_data stih4 - 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; -+extern const struct stmmac_of_data ipq806x_gmac_data; - - #endif /* __STMMAC_PLATFORM_H__ */ ---- /dev/null -+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c -@@ -0,0 +1,343 @@ -+/* -+ * 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 <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/phy.h> -+#include <linux/regmap.h> -+#include <linux/clk.h> -+#include <linux/reset.h> -+#include <linux/of_net.h> -+#include <linux/mfd/syscon.h> -+#include <linux/stmmac.h> -+#include <linux/of_mdio.h> -+ -+#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) (1 << 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_setup(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct ipq806x_gmac *gmac; -+ int val; -+ void *err; -+ -+ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL); -+ if (!gmac) -+ return ERR_PTR(-ENOMEM); -+ -+ gmac->pdev = pdev; -+ -+ err = ipq806x_gmac_of_parse(gmac); -+ if (err) { -+ dev_err(dev, "device tree parsing error\n"); -+ return 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 NULL; -+ } -+ 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 &= ~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 NULL; -+ } -+ 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); -+ } -+ -+ return gmac; -+} -+ -+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed) -+{ -+ struct ipq806x_gmac *gmac = priv; -+ -+ ipq806x_gmac_set_speed(gmac, speed); -+} -+ -+const struct stmmac_of_data ipq806x_gmac_data = { -+ .has_gmac = 1, -+ .setup = ipq806x_gmac_setup, -+ .fix_mac_speed = ipq806x_gmac_fix_mac_speed, -+}; diff --git a/target/linux/ipq806x/patches-4.1/705-net-stmmac-ipq806x-document-device-tree-bindings.patch b/target/linux/ipq806x/patches-4.1/705-net-stmmac-ipq806x-document-device-tree-bindings.patch deleted file mode 100644 index 3144fa36fe..0000000000 --- a/target/linux/ipq806x/patches-4.1/705-net-stmmac-ipq806x-document-device-tree-bindings.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 0f9605d9409b77a89daef91cc68239fc2ff50457 Mon Sep 17 00:00:00 2001 -From: Mathieu Olivari <mathieu@codeaurora.org> -Date: Fri, 8 May 2015 16:51:25 -0700 -Subject: [PATCH 5/8] net: stmmac: ipq806x: document device tree bindings - -Add the device tree bindings documentation for the QCA IPQ806x -variant of the Synopsys DesignWare MAC. - -Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org> ---- - .../devicetree/bindings/net/ipq806x-dwmac.txt | 35 ++++++++++++++++++++++ - 1 file changed, 35 insertions(+) - create mode 100644 Documentation/devicetree/bindings/net/ipq806x-dwmac.txt - ---- /dev/null -+++ b/Documentation/devicetree/bindings/net/ipq806x-dwmac.txt -@@ -0,0 +1,35 @@ -+* IPQ806x DWMAC Ethernet controller -+ -+The device inherits all the properties of the dwmac/stmmac devices -+described in the file net/stmmac.txt with the following changes. -+ -+Required properties: -+ -+- compatible: should be "qcom,ipq806x-gmac" along with "snps,dwmac" -+ and any applicable more detailed version number -+ described in net/stmmac.txt -+ -+- qcom,nss-common: should contain a phandle to a syscon device mapping the -+ nss-common registers. -+ -+- qcom,qsgmii-csr: should contain a phandle to a syscon device mapping the -+ qsgmii-csr registers. -+ -+Example: -+ -+ gmac: ethernet@37000000 { -+ device_type = "network"; -+ compatible = "qcom,ipq806x-gmac"; -+ reg = <0x37000000 0x200000>; -+ interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>; -+ interrupt-names = "macirq"; -+ -+ qcom,nss-common = <&nss_common>; -+ qcom,qsgmii-csr = <&qsgmii_csr>; -+ -+ clocks = <&gcc GMAC_CORE1_CLK>; -+ clock-names = "stmmaceth"; -+ -+ resets = <&gcc GMAC_CORE1_RESET>; -+ reset-names = "stmmaceth"; -+ }; diff --git a/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch b/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch index 84c15c7566..d385c9a36c 100644 --- a/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch +++ b/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch @@ -9,27 +9,23 @@ Subject: [PATCH] stmac: platform: add support for retreiving mac from mtd --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c -@@ -302,6 +302,7 @@ static int stmmac_pltfr_probe(struct pla - struct stmmac_priv *priv = NULL; - struct plat_stmmacenet_data *plat_dat = NULL; - const char *mac = NULL; -+ u8 mtd_mac[ETH_ALEN] = { }; - int irq, wol_irq, lpi_irq; +@@ -116,6 +116,19 @@ stmmac_probe_config_dt(struct platform_d + return ERR_PTR(-ENOMEM); - /* Get IRQ information early to have an ability to ask for deferred -@@ -362,6 +363,15 @@ static int stmmac_pltfr_probe(struct pla - pr_err("%s: main dt probe failed", __func__); - return ret; - } + *mac = of_get_mac_address(np); ++ if (!*mac) { ++ u8 mtd_mac[ETH_ALEN]; ++ int ret; + -+ if (!mac) { -+ ret = of_get_mac_address_mtd(dev->of_node, &mtd_mac); -+ if (ret == -EPROBE_DEFER) -+ return ret; ++ ret = of_get_mac_address_mtd(np, mtd_mac); ++ if (ret == -EPROBE_DEFER) ++ return ERR_PTR(ret); + -+ if (is_valid_ether_addr(&mtd_mac)) -+ mac = mtd_mac; -+ } - } ++ if (is_valid_ether_addr(mtd_mac)) ++ *mac = devm_kmemdup(&pdev->dev, mtd_mac, ETH_ALEN, ++ GFP_KERNEL); ++ } ++ + plat->interface = of_get_phy_mode(np); - /* Custom setup (if needed) */ + /* Get max speed of operation from device tree */ |