Thread (31 messages) 31 messages, 8 authors, 2016-09-04

[PATCH RFC 2/3] net: stmmac: add a glue driver for the Amlogic Meson 8b / GXBB DWMAC

STALE3682d

From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: 2016-06-25 16:50:25
Also in: linux-amlogic
Subsystem: networking drivers, open firmware and flattened device tree bindings, stmmac ethernet driver, the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Maxime Chevallier, Linus Torvalds

The Ethernet controller available in Meson8b and GXBB SoCs is a Synopsys
DesignWare MAC IP core which is already supported by the stmmac driver.

In addition to the standard stmmac driver some Meson8b / GXBB specific
registers have to be configured for the PHY clocks. These SoC specific
registers are called PRG_ETHERNET_ADDR0 and PRG_ETHERNET_ADDR1 in the
datasheet.
These registers are not backwards compatible with those on Meson 6b,
which is why a new glue driver was introduced.

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
 drivers/net/ethernet/stmicro/stmmac/Makefile       |   2 +-
 .../net/ethernet/stmicro/stmmac/dwmac-meson8b.c    | 219 +++++++++++++++++++++
 include/dt-bindings/net/amlogic-meson8b-dwmac.h    |  33 ++++
 3 files changed, 253 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
 create mode 100644 include/dt-bindings/net/amlogic-meson8b-dwmac.h
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index 0fb362d..79e5d0c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -9,7 +9,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o	\
 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_MESON)	+= dwmac-meson.o dwmac-meson8b.o
 obj-$(CONFIG_DWMAC_ROCKCHIP)	+= dwmac-rk.o
 obj-$(CONFIG_DWMAC_SOCFPGA)	+= dwmac-socfpga.o
 obj-$(CONFIG_DWMAC_STI)		+= dwmac-sti.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
new file mode 100644
index 0000000..4c2d1e1
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
@@ -0,0 +1,219 @@
+/*
+ * Amlogic Meson S805/S905 DWMAC glue layer
+ *
+ * Copyright (C) 20016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/device.h>
+#include <linux/ethtool.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/stmmac.h>
+
+#include "stmmac_platform.h"
+
+#define PRG_ETH0			0x0
+#define PRG_ETH0_RGMII_MODE		BIT(0)
+#define PRG_ETH0_TXDLY_SHIFT		5 /* 2 bits [5-6] */
+#define PRG_ETH0_TXDLY_MASK		(0x3 << PRG_ETH0_TXDLY_SHIFT)
+#define PRG_ETH0_MP2_CLK_SHIFT		7 /* 3 bits [7-9] */
+#define PRG_ETH0_MP2_CLK_MASK		(0x7 << PRG_ETH0_MP2_CLK_SHIFT)
+#define PRG_ETH0_GEN_25MHZ_PHY_CLK	BIT(10)
+#define PRG_ETH0_TX_CLK_SPEED_100	BIT(11)
+#define PRG_ETH0_TX_AND_PHY_REF_CLK	BIT(12)
+
+struct meson8b_dwmac {
+	struct platform_device	*pdev;
+	struct regmap		*prg_ethernet;
+	phy_interface_t		phy_mode;
+	u32			tx_delay;
+	u32			mp2_clk;
+	bool			enable_25mhz_phy_clk;
+};
+
+static void meson8b_dwmac_fix_mac_speed(void *priv, unsigned int speed)
+{
+	struct meson8b_dwmac *dwmac = priv;
+
+	/* MAC speed adjustment is only needed in RMII mode */
+	if (dwmac->phy_mode != PHY_INTERFACE_MODE_RMII)
+		return;
+
+	switch (speed) {
+	case SPEED_10:
+		/* 2.5MHz */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_TX_CLK_SPEED_100, 0);
+		break;
+	case SPEED_100:
+		/* 25MHz */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_TX_CLK_SPEED_100,
+				   PRG_ETH0_TX_CLK_SPEED_100);
+		break;
+	}
+}
+
+static int meson8b_dwmac_of_parse(struct meson8b_dwmac *dwmac)
+{
+	struct device *dev = &dwmac->pdev->dev;
+	struct device_node *np = dev->of_node;
+
+	dwmac->phy_mode = of_get_phy_mode(np);
+	if (dwmac->phy_mode < 0) {
+		dev_err(dev, "missing phy-mode property\n");
+		return -EINVAL;
+	}
+
+	/* register map for MAC configuration */
+	dwmac->prg_ethernet = syscon_regmap_lookup_by_phandle(np,
+					"amlogic,prg-ethernet");
+	if (IS_ERR(dwmac->prg_ethernet)) {
+		dev_err(dev, "missing amlogic,prg-ethernet property\n");
+		return PTR_ERR(dwmac->prg_ethernet);
+	}
+
+	if (of_property_read_bool(np, "amlogic,enable-25mhz-phy-clk"))
+		dwmac->enable_25mhz_phy_clk = true;
+
+	/* TX delay is optional */
+	of_property_read_u32(np, "amlogic,tx-delay", &dwmac->tx_delay);
+
+	/* MP2 clock is optional at least in RMII mode */
+	of_property_read_u32(np, "amlogic,mp2-clock", &dwmac->mp2_clk);
+
+	return 0;
+}
+
+static int meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
+{
+	switch (dwmac->phy_mode) {
+	case PHY_INTERFACE_MODE_RGMII:
+	case PHY_INTERFACE_MODE_RGMII_ID:
+	case PHY_INTERFACE_MODE_RGMII_RXID:
+	case PHY_INTERFACE_MODE_RGMII_TXID:
+		/* enable RGMII mode */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_RGMII_MODE,
+				   PRG_ETH0_RGMII_MODE);
+
+		/* only relevant for RMII mode -> disable in RGMII mode */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_TX_CLK_SPEED_100, 0);
+
+		/* TX clock delay (ranges from 0 to 3/4 clock cycles) */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_TXDLY_MASK,
+				   dwmac->tx_delay << PRG_ETH0_TXDLY_SHIFT);
+		break;
+
+	case PHY_INTERFACE_MODE_RMII:
+		/* disable RGMII mode -> enables RMII mode */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_RGMII_MODE, 0);
+
+		/* default to 100Mbit mode */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_TX_CLK_SPEED_100,
+				   PRG_ETH0_TX_CLK_SPEED_100);
+
+		/* TX clock delay cannot be configured in RMII mode */
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_TXDLY_MASK, 0);
+
+		break;
+
+	default:
+		dev_err(&dwmac->pdev->dev, "unsupported phy-mode %s\n",
+			phy_modes(dwmac->phy_mode));
+		return -EINVAL;
+	}
+
+	/* mp2_clk is the factor for mp2_clk_out, rate = 250MHz * factor */
+	regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0, PRG_ETH0_MP2_CLK_MASK,
+			   dwmac->mp2_clk << PRG_ETH0_MP2_CLK_SHIFT);
+
+	/* should we generate 25MHz for the PHY? */
+	if (dwmac->enable_25mhz_phy_clk)
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_GEN_25MHZ_PHY_CLK,
+				   PRG_ETH0_GEN_25MHZ_PHY_CLK);
+	else
+		regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+				   PRG_ETH0_GEN_25MHZ_PHY_CLK, 0);
+
+	/* enable TX_CLK and PHY_REF_CLK generator */
+	regmap_update_bits(dwmac->prg_ethernet, PRG_ETH0,
+			   PRG_ETH0_TX_AND_PHY_REF_CLK,
+			   PRG_ETH0_TX_AND_PHY_REF_CLK);
+
+	return 0;
+}
+
+static int meson8b_dwmac_probe(struct platform_device *pdev)
+{
+	struct plat_stmmacenet_data *plat_dat;
+	struct stmmac_resources stmmac_res;
+	struct meson8b_dwmac *dwmac;
+	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 -ENOMEM;
+
+	dwmac->pdev = pdev;
+
+	ret = meson8b_dwmac_of_parse(dwmac);
+	if (ret)
+		return ret;
+
+	ret = meson8b_init_prg_eth(dwmac);
+	if (ret)
+		return ret;
+
+	plat_dat->bsp_priv = dwmac;
+	plat_dat->fix_mac_speed = meson8b_dwmac_fix_mac_speed;
+
+	return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+}
+
+static const struct of_device_id meson8b_dwmac_match[] = {
+	{ .compatible = "amlogic,meson8b-dwmac" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, meson8b_dwmac_match);
+
+static struct platform_driver meson8b_dwmac_driver = {
+	.probe  = meson8b_dwmac_probe,
+	.remove = stmmac_pltfr_remove,
+	.driver = {
+		.name           = "meson8b-dwmac",
+		.pm		= &stmmac_pltfr_pm_ops,
+		.of_match_table = meson8b_dwmac_match,
+	},
+};
+module_platform_driver(meson8b_dwmac_driver);
+
+MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
+MODULE_DESCRIPTION("Amlogic Meson S805/S905 DWMAC glue layer");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/net/amlogic-meson8b-dwmac.h b/include/dt-bindings/net/amlogic-meson8b-dwmac.h
new file mode 100644
index 0000000..413ef4e
--- /dev/null
+++ b/include/dt-bindings/net/amlogic-meson8b-dwmac.h
@@ -0,0 +1,33 @@
+/*
+ * Device Tree constants for the Amlogic Meson S805/S905 DWMAC
+ *
+ * Copyright (C) 20016 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _DT_BINDINGS_AMLOGIC_MESON8B_DWMAC_H
+#define _DT_BINDINGS_AMLOGIC_MESON8B_DWMAC_H
+
+/* TX delay settings */
+#define MESON8B_DWMAC_TX_CLK_DELAY_OFF				0x0
+#define MESON8B_DWMAC_TX_CLK_DELAY_QUARTER_CYCLE		0x1
+#define MESON8B_DWMAC_TX_CLK_DELAY_HALF_CYCLE			0x2
+#define MESON8B_DWMAC_TX_CLK_DELAY_THREE_QUARTER_CYCLEs		0x3
+
+/* mp2 clock rates */
+#define MESON8B_DWMAC_MP2_CLOCK_DISABLED	0
+#define MESON8B_DWMAC_MP2_CLOCK_250MHZ		1
+#define MESON8B_DWMAC_MP2_CLOCK_500MHZ		2
+#define MESON8B_DWMAC_MP2_CLOCK_750MHZ		3
+#define MESON8B_DWMAC_MP2_CLOCK_1000MHZ		4
+#define MESON8B_DWMAC_MP2_CLOCK_1250MHZ		5
+#define MESON8B_DWMAC_MP2_CLOCK_1500MHZ		6
+#define MESON8B_DWMAC_MP2_CLOCK_1750MHZ		7
+
+#endif /* _DT_BINDINGS_AMLOGIC_MESON8B_DWMAC_H */
-- 
2.9.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help