summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Trumtrar <s.trumtrar@pengutronix.de>2018-01-10 09:14:18 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2018-01-11 09:34:33 +0100
commit3b6f631bfd2d5d80a4be338ee8947863e6f4e445 (patch)
tree7c395bf017085a9786eb0fea16b254bb14302549
parentc1f902841ce3c759a4dddbf02ccc8012e4c50162 (diff)
downloadbarebox-3b6f631bfd2d5d80a4be338ee8947863e6f4e445.tar.gz
barebox-3b6f631bfd2d5d80a4be338ee8947863e6f4e445.tar.xz
net: add SoCFPGA-specific designware driver
Add a driver for the SoCFPGA-specific version of the designware ethernet ip core. Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--arch/arm/mach-socfpga/include/mach/cyclone5-system-manager.h3
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/designware_socfpga.c184
4 files changed, 195 insertions, 0 deletions
diff --git a/arch/arm/mach-socfpga/include/mach/cyclone5-system-manager.h b/arch/arm/mach-socfpga/include/mach/cyclone5-system-manager.h
index 9efc37a4dc..24f52effd8 100644
--- a/arch/arm/mach-socfpga/include/mach/cyclone5-system-manager.h
+++ b/arch/arm/mach-socfpga/include/mach/cyclone5-system-manager.h
@@ -65,4 +65,7 @@ void socfpga_sysmgr_pinmux_init(unsigned long *sys_mgr_init_table, int num);
#define SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB 2
#define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003
+#define SYSMGR_FPGAGRP_MODULE 0x00000028
+#define SYSMGR_FPGAGRP_MODULE_EMAC 0x00000004
+
#endif /* _SYSTEM_MANAGER_H_ */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 36b257f43e..09676b3d60 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -79,6 +79,13 @@ config DRIVER_NET_DESIGNWARE_GENERIC
This option enables support for the Synopsys
Designware Core Univesal MAC 10M/100M/1G ethernet IP on SoCFPGA.
+config DRIVER_NET_DESIGNWARE_SOCFPGA
+ bool "Designware Universal MAC ethernet driver for SoCFPGA platforms"
+ depends on ARCH_SOCFPGA
+ help
+ This option enables support for the Synopsys
+ Designware Core Univesal MAC 10M/100M/1G ethernet IP on SoCFPGA.
+
endif
config DRIVER_NET_DM9K
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index eb07434ab4..304bbba02d 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_DRIVER_NET_CPSW) += cpsw.o
obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC) += davinci_emac.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE) += designware.o
obj-$(CONFIG_DRIVER_NET_DESIGNWARE_GENERIC) += designware_generic.o
+obj-$(CONFIG_DRIVER_NET_DESIGNWARE_SOCFPGA) += designware_socfpga.o
obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o
obj-$(CONFIG_DRIVER_NET_E1000) += e1000/regio.o e1000/main.o e1000/eeprom.o
obj-$(CONFIG_DRIVER_NET_ENC28J60) += enc28j60.o
diff --git a/drivers/net/designware_socfpga.c b/drivers/net/designware_socfpga.c
new file mode 100644
index 0000000000..154c38f9a1
--- /dev/null
+++ b/drivers/net/designware_socfpga.c
@@ -0,0 +1,184 @@
+/*
+ * (C) Copyright 2010
+ * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/*
+ * Designware ethernet IP driver for u-boot
+ */
+
+#include <common.h>
+#include <init.h>
+#include <io.h>
+#include <net.h>
+#include <of_net.h>
+#include <linux/reset.h>
+#include <mach/cyclone5-system-manager.h>
+#include <mfd/syscon.h>
+#include "designware.h"
+
+#define SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK 0x00000010
+
+struct socfpga_dwc_dev {
+ struct dw_eth_dev *priv;
+ u32 reg_offset;
+ u32 reg_shift;
+ void __iomem *sys_mgr_base;
+ bool f2h_ptp_ref_clk;
+};
+
+static int socfpga_dwc_set_phy_mode(struct socfpga_dwc_dev *dwc_dev)
+{
+ struct dw_eth_dev *eth_dev = dwc_dev->priv;
+ int phymode = eth_dev->interface;
+ u32 reg_offset = dwc_dev->reg_offset;
+ u32 reg_shift = dwc_dev->reg_shift;
+ u32 ctrl, val;
+
+ switch (phymode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_ID:
+ val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
+ case PHY_INTERFACE_MODE_SGMII:
+ val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII;
+ break;
+ default:
+ dev_err(&eth_dev->netdev.dev, "bad phy mode %d\n", phymode);
+ return -EINVAL;
+ }
+
+ /* Assert reset to the enet controller before changing the phy mode */
+ if (eth_dev->rst)
+ reset_control_assert(eth_dev->rst);
+
+ ctrl = readl(dwc_dev->sys_mgr_base + reg_offset);
+ ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift);
+ ctrl |= val << reg_shift;
+
+ if (dwc_dev->f2h_ptp_ref_clk ||
+ phymode == PHY_INTERFACE_MODE_MII ||
+ phymode == PHY_INTERFACE_MODE_GMII ||
+ phymode == PHY_INTERFACE_MODE_SGMII) {
+ u32 module;
+
+ ctrl |= SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2);
+ module = readl(dwc_dev->sys_mgr_base + SYSMGR_FPGAGRP_MODULE);
+ module |= (SYSMGR_FPGAGRP_MODULE_EMAC << (reg_shift / 2));
+
+ writel(module, dwc_dev->sys_mgr_base + SYSMGR_FPGAGRP_MODULE);
+ } else {
+ ctrl &= ~(SYSMGR_EMACGRP_CTRL_PTP_REF_CLK_MASK << (reg_shift / 2));
+ }
+
+ writel(ctrl, dwc_dev->sys_mgr_base + reg_offset);
+
+ /* Deassert reset for the phy configuration to be sampled by
+ * the enet controller, and operation to start in requested mode
+ */
+ if (eth_dev->rst)
+ reset_control_deassert(eth_dev->rst);
+
+ return 0;
+}
+
+static int socfpga_dwc_probe_dt(struct device_d *dev, struct socfpga_dwc_dev *priv)
+{
+ u32 reg_offset, reg_shift;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_OFTREE))
+ return -ENODEV;
+
+ ret = of_property_read_u32_index(dev->device_node, "altr,sysmgr-syscon",
+ 1, &reg_offset);
+ if (ret) {
+ dev_err(dev, "Could not read reg_offset from sysmgr-syscon! Please update the devicetree.\n");
+
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(dev->device_node, "altr,sysmgr-syscon",
+ 2, &reg_shift);
+ if (ret) {
+ dev_err(dev, "Could not read reg_shift from sysmgr-syscon! Please update the devicetree.\n");
+ return -EINVAL;
+ }
+
+ priv->f2h_ptp_ref_clk = of_property_read_bool(dev->device_node, "altr,f2h_ptp_ref_clk");
+
+ priv->reg_offset = reg_offset;
+ priv->reg_shift = reg_shift;
+
+ return 0;
+}
+
+static int socfpga_dwc_ether_probe(struct device_d *dev)
+{
+ struct socfpga_dwc_dev *dwc_dev;
+ struct dw_eth_dev *priv;
+ int ret;
+
+ dwc_dev = xzalloc(sizeof(*dwc_dev));
+
+ priv = dwc_drv_probe(dev);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ priv->rst = reset_control_get(dev, NULL);
+ if (IS_ERR(priv->rst))
+ dev_warn(dev, "No reset lines.\n");
+
+ dwc_dev->priv = priv;
+
+ dwc_dev->sys_mgr_base = syscon_base_lookup_by_phandle(dev->device_node,
+ "altr,sysmgr-syscon");
+ if (IS_ERR(dwc_dev->sys_mgr_base)) {
+ dev_err(dev, "Could not get sysmgr-syscon node\n");
+ return PTR_ERR(dwc_dev->sys_mgr_base);
+ }
+
+ ret = socfpga_dwc_probe_dt(dev, dwc_dev);
+ if (ret)
+ return ret;
+
+ socfpga_dwc_set_phy_mode(dwc_dev);
+
+ return 0;
+}
+
+static struct dw_eth_drvdata socfpga_stmmac_drvdata = {
+ .enh_desc = 1,
+};
+
+static __maybe_unused struct of_device_id socfpga_dwc_ether_compatible[] = {
+ {
+ .compatible = "altr,socfpga-stmmac",
+ .data = &socfpga_stmmac_drvdata,
+ }, {
+ /* sentinel */
+ }
+};
+
+static struct driver_d socfpga_dwc_ether_driver = {
+ .name = "socfpga_designware_eth",
+ .probe = socfpga_dwc_ether_probe,
+ .of_compatible = DRV_OF_COMPAT(socfpga_dwc_ether_compatible),
+};
+device_platform_driver(socfpga_dwc_ether_driver);