diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro')
20 files changed, 1098 insertions, 253 deletions
diff --git a/drivers/net/ethernet/stmicro/Kconfig b/drivers/net/ethernet/stmicro/Kconfig index f4a80da00..1c1157d2b 100644 --- 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 diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index 7d3af190b..cec147d1d 100644 --- 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 diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index 73c2715a2..b3901616f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/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/drivers/net/ethernet/stmicro/stmmac/descs.h b/drivers/net/ethernet/stmicro/stmmac/descs.h index ad3996038..799c2929c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/descs.h +++ b/drivers/net/ethernet/stmicro/stmmac/descs.h @@ -158,6 +158,8 @@ struct dma_desc { u32 buffer2_size:13; u32 reserved4:3; } etx; /* -- enhanced -- */ + + u64 all_flags; } des01; unsigned int des2; unsigned int des3; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c new file mode 100644 index 000000000..e817a1a44 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c @@ -0,0 +1,41 @@ +/* + * 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 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 = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c new file mode 100644 index 000000000..f0e4bb4e3 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c @@ -0,0 +1,365 @@ +/* + * 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_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 &= ~(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 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); +} + +static const struct stmmac_of_data ipq806x_gmac_data = { + .has_gmac = 1, + .setup = ipq806x_gmac_setup, + .fix_mac_speed = ipq806x_gmac_fix_mac_speed, +}; + +static const struct of_device_id ipq806x_gmac_dwmac_match[] = { + { .compatible = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data }, + { } +}; +MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match); + +static struct platform_driver ipq806x_gmac_dwmac_driver = { + .probe = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c new file mode 100644 index 000000000..cb888d3eb --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c @@ -0,0 +1,99 @@ +/* + * 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 + +struct lpc18xx_dwmac_priv_data { + struct regmap *reg; + int interface; +}; + +static void *lpc18xx_dwmac_setup(struct platform_device *pdev) +{ + struct lpc18xx_dwmac_priv_data *dwmac; + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return ERR_PTR(-ENOMEM); + + dwmac->interface = of_get_phy_mode(pdev->dev.of_node); + if (dwmac->interface < 0) + return ERR_PTR(dwmac->interface); + + dwmac->reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); + if (IS_ERR(dwmac->reg)) { + dev_err(&pdev->dev, "Syscon lookup failed\n"); + return dwmac->reg; + } + + return dwmac; +} + +static int lpc18xx_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct lpc18xx_dwmac_priv_data *dwmac = priv; + u8 ethmode; + + if (dwmac->interface == PHY_INTERFACE_MODE_MII) { + ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII; + } else if (dwmac->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(dwmac->reg, LPC18XX_CREG_CREG6, + LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); + + return 0; +} + +static const struct stmmac_of_data lpc18xx_dwmac_data = { + .has_gmac = 1, + .setup = lpc18xx_dwmac_setup, + .init = lpc18xx_dwmac_init, +}; + +static const struct of_device_id lpc18xx_dwmac_match[] = { + { .compatible = "nxp,lpc1850-dwmac", .data = &lpc18xx_dwmac_data }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); + +static struct platform_driver lpc18xx_dwmac_driver = { + .probe = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index cca028d63..61a324a87 100644 --- 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> @@ -63,7 +64,28 @@ static void *meson6_dwmac_setup(struct platform_device *pdev) return dwmac; } -const struct stmmac_of_data meson6_dwmac_data = { +static 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", .data = &meson6_dwmac_data}, + { } +}; +MODULE_DEVICE_TABLE(of, meson6_dwmac_match); + +static struct platform_driver meson6_dwmac_driver = { + .probe = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 6249a4ec0..00a1e1e09 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -22,23 +22,36 @@ #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; + struct rk_gmac_ops *ops; bool clk_enabled; bool clock_input; struct clk *clk_mac; - struct clk *clk_mac_pll; struct clk *gmac_clkin; struct clk *mac_clk_rx; struct clk *mac_clk_tx; @@ -61,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); } } +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); + } +} + +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; @@ -166,49 +304,49 @@ 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_pll, 50000000); + clk_set_rate(bsp_priv->clk_mac, 50000000); } return 0; @@ -292,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, + struct rk_gmac_ops *ops) { struct rk_priv_data *bsp_priv; struct device *dev = &pdev->dev; @@ -324,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)) { @@ -337,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 @@ -352,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; } @@ -377,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); @@ -391,6 +529,16 @@ static void *rk_gmac_setup(struct platform_device *pdev) return bsp_priv; } +static void *rk3288_gmac_setup(struct platform_device *pdev) +{ + return rk_gmac_setup(pdev, &rk3288_ops); +} + +static void *rk3368_gmac_setup(struct platform_device *pdev) +{ + return rk_gmac_setup(pdev, &rk3368_ops); +} + static int rk_gmac_init(struct platform_device *pdev, void *priv) { struct rk_priv_data *bsp_priv = priv; @@ -421,17 +569,47 @@ 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 = { +static const struct stmmac_of_data rk3288_gmac_data = { .has_gmac = 1, .fix_mac_speed = rk_fix_speed, - .setup = rk_gmac_setup, + .setup = rk3288_gmac_setup, .init = rk_gmac_init, .exit = rk_gmac_exit, }; + +static const struct stmmac_of_data rk3368_gmac_data = { + .has_gmac = 1, + .fix_mac_speed = rk_fix_speed, + .setup = rk3368_gmac_setup, + .init = rk_gmac_init, + .exit = rk_gmac_exit, +}; + +static const struct of_device_id rk_gmac_dwmac_match[] = { + { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data}, + { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_gmac_data}, + { } +}; +MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match); + +static struct platform_driver rk_gmac_dwmac_driver = { + .probe = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index 5a36bd2c7..8141c5b84 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c @@ -257,9 +257,28 @@ static int socfpga_dwmac_init(struct platform_device *pdev, void *priv) return ret; } -const struct stmmac_of_data socfpga_gmac_data = { +static 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 const struct of_device_id socfpga_dwmac_match[] = { + { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data }, + { } +}; +MODULE_DEVICE_TABLE(of, socfpga_dwmac_match); + +static struct platform_driver socfpga_dwmac_driver = { + .probe = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c index bb6e2dc61..a2e8111c5 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -17,6 +17,7 @@ #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> @@ -351,16 +352,40 @@ static void *sti_dwmac_setup(struct platform_device *pdev) return dwmac; } -const struct stmmac_of_data stih4xx_dwmac_data = { +static 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, }; -const struct stmmac_of_data stid127_dwmac_data = { +static 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 = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c index c5ea9ab75..15048ca39 100644 --- 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> @@ -132,7 +134,7 @@ 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 = { +static const struct stmmac_of_data sun7i_gmac_data = { .has_gmac = 1, .tx_coe = 1, .fix_mac_speed = sun7i_fix_speed, @@ -140,3 +142,24 @@ const struct stmmac_of_data sun7i_gmac_data = { .init = sun7i_gmac_init, .exit = sun7i_gmac_exit, }; + +static const struct of_device_id sun7i_dwmac_match[] = { + { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, + { } +}; +MODULE_DEVICE_TABLE(of, sun7i_dwmac_match); + +static struct platform_driver sun7i_dwmac_driver = { + .probe = stmmac_pltfr_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/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index 1e2bcf5f8..7d944449f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -240,6 +240,7 @@ static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x, static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode, int end) { + p->des01.all_flags = 0; p->des01.erx.own = 1; p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1; @@ -254,7 +255,7 @@ static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end) { - p->des01.etx.own = 0; + p->des01.all_flags = 0; if (mode == STMMAC_CHAIN_MODE) ehn_desc_tx_set_on_chain(p, end); else diff --git a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c index 08c483bd2..3f20bb1fe 100644 --- 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, 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/drivers/net/ethernet/stmicro/stmmac/norm_desc.c b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c index 35ad4f427..48c345644 100644 --- a/drivers/net/ethernet/stmicro/stmmac/norm_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/norm_desc.c @@ -123,6 +123,7 @@ static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode, int end) { + p->des01.all_flags = 0; p->des01.rx.own = 1; p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1; @@ -137,7 +138,7 @@ static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode, static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end) { - p->des01.tx.own = 0; + p->des01.all_flags = 0; if (mode == STMMAC_CHAIN_MODE) ndesc_tx_set_on_chain(p, end); else diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 73bab983e..1f3b33a6c 100644 --- 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_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/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 2c5ce2bac..864b476f7 100644 --- 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_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(phydev)) { pr_err("%s: Could not attach to PHY\n", dev->name); @@ -848,7 +856,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; } @@ -975,13 +983,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, @@ -1189,41 +1195,41 @@ static int alloc_dma_desc_resources(struct stmmac_priv *priv) goto err_tx_skbuff; if (priv->extend_desc) { - priv->dma_erx = dma_alloc_coherent(priv->device, rxsize * - sizeof(struct - dma_extended_desc), - &priv->dma_rx_phy, - GFP_KERNEL); + priv->dma_erx = dma_zalloc_coherent(priv->device, rxsize * + sizeof(struct + dma_extended_desc), + &priv->dma_rx_phy, + GFP_KERNEL); if (!priv->dma_erx) goto err_dma; - priv->dma_etx = dma_alloc_coherent(priv->device, txsize * - sizeof(struct - dma_extended_desc), - &priv->dma_tx_phy, - GFP_KERNEL); + priv->dma_etx = dma_zalloc_coherent(priv->device, txsize * + sizeof(struct + dma_extended_desc), + &priv->dma_tx_phy, + GFP_KERNEL); if (!priv->dma_etx) { dma_free_coherent(priv->device, priv->dma_rx_size * - sizeof(struct dma_extended_desc), - priv->dma_erx, priv->dma_rx_phy); + sizeof(struct dma_extended_desc), + priv->dma_erx, priv->dma_rx_phy); goto err_dma; } } else { - priv->dma_rx = dma_alloc_coherent(priv->device, rxsize * - sizeof(struct dma_desc), - &priv->dma_rx_phy, - GFP_KERNEL); + priv->dma_rx = dma_zalloc_coherent(priv->device, rxsize * + sizeof(struct dma_desc), + &priv->dma_rx_phy, + GFP_KERNEL); if (!priv->dma_rx) goto err_dma; - priv->dma_tx = dma_alloc_coherent(priv->device, txsize * - sizeof(struct dma_desc), - &priv->dma_tx_phy, - GFP_KERNEL); + priv->dma_tx = dma_zalloc_coherent(priv->device, txsize * + sizeof(struct dma_desc), + &priv->dma_tx_phy, + GFP_KERNEL); if (!priv->dma_tx) { dma_free_coherent(priv->device, priv->dma_rx_size * - sizeof(struct dma_desc), - priv->dma_rx, priv->dma_rx_phy); + sizeof(struct dma_desc), + priv->dma_rx, priv->dma_rx_phy); goto err_dma; } } @@ -2800,16 +2806,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; @@ -2817,7 +2822,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); @@ -2828,8 +2833,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(); @@ -2944,7 +2958,7 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, } } - return priv; + return 0; error_mdio_register: unregister_netdev(ndev); @@ -2957,7 +2971,7 @@ error_pclk_get: error_clk_get: free_netdev(ndev); - return ERR_PTR(ret); + return ret; } EXPORT_SYMBOL_GPL(stmmac_dvr_probe); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index 3bca90871..d71a721ea 100644 --- 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_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/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 68aec5c46..bcdc8955c 100644 --- 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 /** @@ -129,14 +111,9 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, struct device_node *np = pdev->dev.of_node; struct stmmac_dma_cfg *dma_cfg; const struct of_device_id *device; + struct device *dev = &pdev->dev; - if (!np) - return -ENODEV; - - device = of_match_device(stmmac_dt_ids, &pdev->dev); - if (!device) - return -ENODEV; - + device = of_match_device(dev->driver->of_match_table, dev); if (device->data) { const struct stmmac_of_data *data = device->data; plat->has_gmac = data->has_gmac; @@ -168,13 +145,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 -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 = @@ -232,8 +220,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) + if (!dma_cfg) { + of_node_put(np); return -ENOMEM; + } plat->dma_cfg = dma_cfg; of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); dma_cfg->fixed_burst = @@ -268,27 +258,26 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, * 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_pltfr_probe(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) { + stmmac_res.irq = platform_get_irq_byname(pdev, "macirq"); + if (stmmac_res.irq < 0) { + if (stmmac_res.irq != -EPROBE_DEFER) { dev_err(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,21 +287,21 @@ 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); + stmmac_res.addr = devm_ioremap_resource(dev, res); + if (IS_ERR(stmmac_res.addr)) + return PTR_ERR(stmmac_res.addr); plat_dat = dev_get_platdata(&pdev->dev); @@ -332,7 +321,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) plat_dat->unicast_filter_entries = 1; if (pdev->dev.of_node) { - ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); + ret = stmmac_probe_config_dt(pdev, plat_dat, &stmmac_res.mac); if (ret) { pr_err("%s: main dt probe failed", __func__); return ret; @@ -353,27 +342,9 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) 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 stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } +EXPORT_SYMBOL_GPL(stmmac_pltfr_probe); /** * stmmac_pltfr_remove @@ -381,7 +352,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); @@ -395,6 +366,7 @@ static int stmmac_pltfr_remove(struct platform_device *pdev) return ret; } +EXPORT_SYMBOL_GPL(stmmac_pltfr_remove); #ifdef CONFIG_PM_SLEEP /** @@ -438,21 +410,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/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 093eb99e5..71da86d7b 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -19,11 +19,8 @@ #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; +int stmmac_pltfr_probe(struct platform_device *pdev); +int stmmac_pltfr_remove(struct platform_device *pdev); +extern const struct dev_pm_ops stmmac_pltfr_pm_ops; #endif /* __STMMAC_PLATFORM_H__ */ |