diff options
Diffstat (limited to 'kernel/drivers/net/ethernet/stmicro')
19 files changed, 1341 insertions, 444 deletions
diff --git a/kernel/drivers/net/ethernet/stmicro/Kconfig b/kernel/drivers/net/ethernet/stmicro/Kconfig index f4a80da00..1c1157d2b 100644 --- a/kernel/drivers/net/ethernet/stmicro/Kconfig +++ b/kernel/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 diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/Kconfig b/kernel/drivers/net/ethernet/stmicro/stmmac/Kconfig index 7d3af190b..cec147d1d 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/kernel/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 diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/Makefile b/kernel/drivers/net/ethernet/stmicro/stmmac/Makefile index 73c2715a2..b3901616f 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -4,9 +4,17 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ 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 diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c new file mode 100644 index 000000000..b1e5f2470 --- /dev/null +++ b/kernel/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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c new file mode 100644 index 000000000..82de68b1a --- /dev/null +++ b/kernel/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 | + 0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET | + 0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET | + 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET | + 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET | + 0xCul << 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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c new file mode 100644 index 000000000..78e9d1861 --- /dev/null +++ b/kernel/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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index cca028d63..c1bac1912 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/kernel/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(void *priv, unsigned int speed) 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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 573708123..0cd3ecff7 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/kernel/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) - -static void set_to_rgmii(struct rk_priv_data *bsp_priv, - int tx_delay, int rx_delay) +#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 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_data *bsp_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); @@ -215,7 +354,7 @@ static int gmac_clk_init(struct rk_priv_data *bsp_priv) static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable) { - int phy_iface = phy_iface = bsp_priv->phy_iface; + int phy_iface = bsp_priv->phy_iface; if (enable) { if (!bsp_priv->clk_enabled) { @@ -291,26 +430,25 @@ static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable) 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 platform_device *pdev) 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 platform_device *pdev) 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 platform_device *pdev) 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 platform_device *pdev) /*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, unsigned int speed) 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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 5a36bd2c7..401383b25 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -175,31 +175,6 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) 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 platform_device *pdev, void *priv) 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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index bb6e2dc61..58c05acc2 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/kernel/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 *priv, u32 spd) 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 sti_dwmac *dwmac) 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; } @@ -311,16 +299,17 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { const char *rs; + dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; + err = of_property_read_string(np, "st,tx-retime-src", &rs); if (err < 0) { dev_warn(dev, "Use internal clock source\n"); - dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN; - } else if (!strcasecmp(rs, "clk_125")) { - dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; - } else if (!strcasecmp(rs, "txclk")) { - dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; + } else { + if (!strcasecmp(rs, "clk_125")) + dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125; + else if (!strcasecmp(rs, "txclk")) + dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK; } - dwmac->speed = SPEED_1000; } @@ -333,34 +322,80 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, 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, }; -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 sti_dwmac_of_data stid127_dwmac_data = { + .fix_retime_src = stid127_fix_retime_src, }; + +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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index c5ea9ab75..adff46375 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c +++ b/kernel/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,80 @@ static void sun7i_fix_speed(void *priv, unsigned int speed) } } -/* 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; + + ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); + if (ret) + sun7i_gmac_exit(pdev, plat_dat->bsp_priv); + + return ret; +} + +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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/kernel/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 08c483bd2..3f20bb1fe 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/mmc_core.c +++ b/kernel/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, struct stmmac_counters *mmc) 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); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 73bab983e..1f3b33a6c 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/kernel/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_priv *priv); 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); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 771cda2a4..2e51b816a 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -721,10 +721,13 @@ static int stmmac_get_ts_info(struct net_device *dev, { struct stmmac_priv *priv = netdev_priv(dev); - if ((priv->hwts_tx_en) && (priv->hwts_rx_en)) { + if ((priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) { - info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_SOFTWARE | SOF_TIMESTAMPING_RAW_HARDWARE; if (priv->ptp_clock) diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index c274cdc5d..a5b869eb4 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/kernel/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) @@ -184,7 +185,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv) priv->clk_csr = STMMAC_CSR_100_150M; else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M)) priv->clk_csr = STMMAC_CSR_150_250M; - else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M)) + else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M)) priv->clk_csr = STMMAC_CSR_250_300M; } } @@ -423,7 +424,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) { struct stmmac_priv *priv = netdev_priv(dev); struct hwtstamp_config config; - struct timespec now; + struct timespec64 now; u64 temp = 0; u32 ptp_v2 = 0; u32 tstamp_all = 0; @@ -620,8 +621,10 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) priv->default_addend); /* initialize system time */ - getnstimeofday(&now); - priv->hw->ptp->init_systime(priv->ioaddr, now.tv_sec, + ktime_get_real_ts64(&now); + + /* lower 32 bits of tv_sec are safe until y2106 */ + priv->hw->ptp->init_systime(priv->ioaddr, (u32)now.tv_sec, now.tv_nsec); } @@ -816,18 +819,25 @@ static int stmmac_init_phy(struct net_device *dev) 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 +861,7 @@ static int stmmac_init_phy(struct net_device *dev) * 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 +988,11 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, { 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, @@ -1939,7 +1947,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) { struct stmmac_priv *priv = netdev_priv(dev); unsigned int txsize = priv->dma_tx_size; - unsigned int entry; + int entry; int i, csum_insertion = 0, is_jumbo = 0; int nfrags = skb_shinfo(skb)->nr_frags; struct dma_desc *desc, *first; @@ -2224,6 +2232,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) frame_len = priv->hw->desc->get_rx_frame_len(p, coe); + /* check if frame_len fits the preallocated memory */ + if (frame_len > priv->dma_buf_sz) { + priv->dev->stats.rx_length_errors++; + break; + } + /* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3 * Type frames (LLC/LLC-SNAP) */ @@ -2803,16 +2817,15 @@ static int stmmac_hw_init(struct stmmac_priv *priv) * 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 +2833,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, ndev = alloc_etherdev(sizeof(struct stmmac_priv)); if (!ndev) - return ERR_PTR(-ENOMEM); + return -ENOMEM; SET_NETDEV_DEV(ndev, device); @@ -2831,8 +2844,17 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, 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 +2969,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, } } - return priv; + return 0; error_mdio_register: unregister_netdev(ndev); @@ -2960,7 +2982,7 @@ error_pclk_get: error_clk_get: free_netdev(ndev); - return ERR_PTR(ret); + return ret; } EXPORT_SYMBOL_GPL(stmmac_dvr_probe); @@ -3024,8 +3046,6 @@ int stmmac_suspend(struct net_device *ndev) priv->hw->dma->stop_tx(priv->ioaddr); priv->hw->dma->stop_rx(priv->ioaddr); - stmmac_clear_descriptors(priv); - /* Enable Power down mode by programming the PMT regs */ if (device_may_wakeup(priv->device)) { priv->hw->mac->pmt(priv->hw, priv->wolopts); @@ -3083,9 +3103,15 @@ int stmmac_resume(struct net_device *ndev) netif_device_attach(ndev); - init_dma_desc_rings(ndev, GFP_ATOMIC); + priv->cur_rx = 0; + priv->dirty_rx = 0; + priv->dirty_tx = 0; + priv->cur_tx = 0; + stmmac_clear_descriptors(priv); + stmmac_hw_setup(ndev, false); stmmac_init_tx_coalesce(priv); + stmmac_set_rx_mode(ndev); napi_enable(&priv->napi); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index b735fa22a..bba670c42 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -138,7 +138,6 @@ int stmmac_mdio_reset(struct mii_bus *bus) #ifdef CONFIG_OF if (priv->device->of_node) { - int reset_gpio, active_low; if (data->reset_gpio < 0) { struct device_node *np = priv->device->of_node; @@ -154,19 +153,23 @@ int stmmac_mdio_reset(struct mii_bus *bus) "snps,reset-active-low"); of_property_read_u32_array(np, "snps,reset-delays-us", data->delays, 3); + + if (gpio_request(data->reset_gpio, "mdio-reset")) + return 0; } - reset_gpio = data->reset_gpio; - active_low = data->active_low; + gpio_direction_output(data->reset_gpio, + data->active_low ? 1 : 0); + if (data->delays[0]) + msleep(DIV_ROUND_UP(data->delays[0], 1000)); - if (!gpio_request(reset_gpio, "mdio-reset")) { - gpio_direction_output(reset_gpio, active_low ? 1 : 0); - udelay(data->delays[0]); - gpio_set_value(reset_gpio, active_low ? 0 : 1); - udelay(data->delays[1]); - gpio_set_value(reset_gpio, active_low ? 1 : 0); - udelay(data->delays[2]); - } + gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1); + if (data->delays[1]) + msleep(DIV_ROUND_UP(data->delays[1], 1000)); + + gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0); + if (data->delays[2]) + msleep(DIV_ROUND_UP(data->delays[2], 1000)); } #endif diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 3bca90871..d71a721ea 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -163,7 +163,7 @@ static int stmmac_pci_probe(struct pci_dev *pdev, { 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_dev *pdev, 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); + memset(&res, 0, sizeof(res)); + res.addr = pcim_iomap_table(pdev)[i]; + res.wol_irq = pdev->irq; + res.irq = pdev->irq; - dev_dbg(&pdev->dev, "STMMAC PCI driver registration completed\n"); - - return 0; + return stmmac_dvr_probe(&pdev->dev, plat, &res); } /** diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 68aec5c46..d02691ba3 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/kernel/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_entries(int ucast_entries) * 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 platform_device *pdev, /* 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 platform_device *pdev, */ 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 platform_device *pdev, 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 platform_device *pdev, 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 platform_device *pdev) * 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 platform_device *pdev) * 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 platform_device *pdev) 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 device *dev) } #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"); diff --git a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 093eb99e5..ffeb8d9e2 100644 --- a/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/kernel/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__ */ |