summaryrefslogtreecommitdiffstats
path: root/AllWinner-net-emac.patch
diff options
context:
space:
mode:
Diffstat (limited to 'AllWinner-net-emac.patch')
-rw-r--r--AllWinner-net-emac.patch1427
1 files changed, 0 insertions, 1427 deletions
diff --git a/AllWinner-net-emac.patch b/AllWinner-net-emac.patch
index 6e7438200..e19dfdd4f 100644
--- a/AllWinner-net-emac.patch
+++ b/AllWinner-net-emac.patch
@@ -1,1430 +1,3 @@
-From patchwork Mon May 1 12:45:01 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v5,
- 01/20] net: stmmac: export stmmac_set_mac_addr/stmmac_get_mac_addr
-From: Corentin LABBE <clabbe.montjoie@gmail.com>
-X-Patchwork-Id: 9706455
-Message-Id: <20170501124520.3769-2-clabbe.montjoie@gmail.com>
-To: robh+dt@kernel.org, mark.rutland@arm.com,
- maxime.ripard@free-electrons.com, wens@csie.org,
- linux@armlinux.org.uk, catalin.marinas@arm.com,
- will.deacon@arm.com, peppe.cavallaro@st.com, alexandre.torgue@st.com
-Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
- netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Corentin Labbe <clabbe.montjoie@gmail.com>
-Date: Mon, 1 May 2017 14:45:01 +0200
-
-Thoses symbol will be needed for the dwmac-sun8i ethernet driver.
-For letting it to be build as module, they need to be exported.
-
-Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
----
- drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c | 3 ++-
- 1 file changed, 2 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
-index 38f9430..67af0bd 100644
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
-@@ -248,6 +248,7 @@ void stmmac_set_mac_addr(void __iomem *ioaddr, u8 addr[6],
- data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
- writel(data, ioaddr + low);
- }
-+EXPORT_SYMBOL_GPL(stmmac_set_mac_addr);
-
- /* Enable disable MAC RX/TX */
- void stmmac_set_mac(void __iomem *ioaddr, bool enable)
-@@ -279,4 +280,4 @@ void stmmac_get_mac_addr(void __iomem *ioaddr, unsigned char *addr,
- addr[4] = hi_addr & 0xff;
- addr[5] = (hi_addr >> 8) & 0xff;
- }
--
-+EXPORT_SYMBOL_GPL(stmmac_get_mac_addr);
-
-From patchwork Mon May 1 12:45:02 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v5,02/20] net: stmmac: add optional setup function
-From: Corentin LABBE <clabbe.montjoie@gmail.com>
-X-Patchwork-Id: 9706501
-Message-Id: <20170501124520.3769-3-clabbe.montjoie@gmail.com>
-To: robh+dt@kernel.org, mark.rutland@arm.com,
- maxime.ripard@free-electrons.com, wens@csie.org,
- linux@armlinux.org.uk, catalin.marinas@arm.com,
- will.deacon@arm.com, peppe.cavallaro@st.com, alexandre.torgue@st.com
-Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
- netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Corentin Labbe <clabbe.montjoie@gmail.com>
-Date: Mon, 1 May 2017 14:45:02 +0200
-
-Instead of adding more ifthen logic for adding a new mac_device_info
-setup function, it is easier to add a function pointer to the function
-needed.
-
-Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 4 +++-
- include/linux/stmmac.h | 1 +
- 2 files changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-index cd8c601..b82ab64 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -3947,7 +3947,9 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
- struct mac_device_info *mac;
-
- /* Identify the MAC HW device */
-- if (priv->plat->has_gmac) {
-+ if (priv->plat->setup) {
-+ mac = priv->plat->setup(priv);
-+ } else if (priv->plat->has_gmac) {
- priv->dev->priv_flags |= IFF_UNICAST_FLT;
- mac = dwmac1000_setup(priv->ioaddr,
- priv->plat->multicast_filter_bins,
-diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
-index 3921cb9..8bb550b 100644
---- a/include/linux/stmmac.h
-+++ b/include/linux/stmmac.h
-@@ -177,6 +177,7 @@ struct plat_stmmacenet_data {
- void (*fix_mac_speed)(void *priv, unsigned int speed);
- int (*init)(struct platform_device *pdev, void *priv);
- void (*exit)(struct platform_device *pdev, void *priv);
-+ struct mac_device_info *(*setup)(void *priv);
- void *bsp_priv;
- struct clk *stmmac_clk;
- struct clk *pclk;
-
-From patchwork Mon May 1 12:45:03 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v5,
- 03/20] dt-bindings: net: Add DT bindings documentation for Allwinner
- dwmac-sun8i
-From: Corentin LABBE <clabbe.montjoie@gmail.com>
-X-Patchwork-Id: 9706457
-Message-Id: <20170501124520.3769-4-clabbe.montjoie@gmail.com>
-To: robh+dt@kernel.org, mark.rutland@arm.com,
- maxime.ripard@free-electrons.com, wens@csie.org,
- linux@armlinux.org.uk, catalin.marinas@arm.com,
- will.deacon@arm.com, peppe.cavallaro@st.com, alexandre.torgue@st.com
-Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
- netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Corentin Labbe <clabbe.montjoie@gmail.com>
-Date: Mon, 1 May 2017 14:45:03 +0200
-
-This patch adds documentation for Device-Tree bindings for the
-Allwinner dwmac-sun8i driver.
-
-Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
-Acked-by: Rob Herring <robh@kernel.org>
----
- .../devicetree/bindings/net/dwmac-sun8i.txt | 77 ++++++++++++++++++++++
- 1 file changed, 77 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/net/dwmac-sun8i.txt
-
-diff --git a/Documentation/devicetree/bindings/net/dwmac-sun8i.txt b/Documentation/devicetree/bindings/net/dwmac-sun8i.txt
-new file mode 100644
-index 0000000..05cd067
---- /dev/null
-+++ b/Documentation/devicetree/bindings/net/dwmac-sun8i.txt
-@@ -0,0 +1,77 @@
-+* Allwinner sun8i GMAC ethernet controller
-+
-+This device is a platform glue layer for stmmac.
-+Please see stmmac.txt for the other unchanged properties.
-+
-+Required properties:
-+- compatible: should be one of the following string:
-+ "allwinner,sun8i-a83t-emac"
-+ "allwinner,sun8i-h3-emac"
-+ "allwinner,sun50i-a64-emac"
-+- reg: address and length of the register for the device.
-+- interrupts: interrupt for the device
-+- interrupt-names: should be "macirq"
-+- clocks: A phandle to the reference clock for this device
-+- clock-names: should be "stmmaceth"
-+- resets: A phandle to the reset control for this device
-+- reset-names: should be "stmmaceth"
-+- phy-mode: See ethernet.txt
-+- phy-handle: See ethernet.txt
-+- #address-cells: shall be 1
-+- #size-cells: shall be 0
-+- syscon: A phandle to the syscon of the SoC with one of the following
-+ compatible string:
-+ - allwinner,sun8i-h3-system-controller
-+ - allwinner,sun50i-a64-system-controller
-+ - allwinner,sun8i-a83t-system-controller
-+
-+Optional properties:
-+- allwinner,tx-delay-ps: TX clock delay chain value in ps. Range value is 0-700. Default is 0)
-+- allwinner,rx-delay-ps: RX clock delay chain value in ps. Range value is 0-3100. Default is 0)
-+Both delay properties need to be a multiple of 100.
-+
-+Optional properties for "allwinner,sun8i-h3-emac":
-+- allwinner,leds-active-low: EPHY LEDs are active low
-+
-+Required child node of emac:
-+- mdio bus node: should be named mdio
-+
-+Required properties of the mdio node:
-+- #address-cells: shall be 1
-+- #size-cells: shall be 0
-+
-+The device node referenced by "phy" or "phy-handle" should be a child node
-+of the mdio node. See phy.txt for the generic PHY bindings.
-+
-+Required properties of the phy node with "allwinner,sun8i-h3-emac":
-+- clocks: a phandle to the reference clock for the EPHY
-+- resets: a phandle to the reset control for the EPHY
-+
-+Example:
-+
-+emac: ethernet@1c0b000 {
-+ compatible = "allwinner,sun8i-h3-emac";
-+ syscon = <&syscon>;
-+ reg = <0x01c0b000 0x104>;
-+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "macirq";
-+ resets = <&ccu RST_BUS_EMAC>;
-+ reset-names = "stmmaceth";
-+ clocks = <&ccu CLK_BUS_EMAC>;
-+ clock-names = "stmmaceth";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ phy = <&int_mii_phy>;
-+ phy-mode = "mii";
-+ allwinner,leds-active-low;
-+ mdio: mdio {
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ int_mii_phy: ethernet-phy@1 {
-+ reg = <1>;
-+ clocks = <&ccu CLK_BUS_EPHY>;
-+ resets = <&ccu RST_BUS_EPHY>;
-+ };
-+ };
-+};
-
-From patchwork Mon May 1 12:45:04 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v5, 04/20] dt-bindings: syscon: Add DT bindings documentation for
- Allwinner syscon
-From: Corentin LABBE <clabbe.montjoie@gmail.com>
-X-Patchwork-Id: 9706469
-Message-Id: <20170501124520.3769-5-clabbe.montjoie@gmail.com>
-To: robh+dt@kernel.org, mark.rutland@arm.com,
- maxime.ripard@free-electrons.com, wens@csie.org,
- linux@armlinux.org.uk, catalin.marinas@arm.com,
- will.deacon@arm.com, peppe.cavallaro@st.com, alexandre.torgue@st.com
-Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
- netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Corentin Labbe <clabbe.montjoie@gmail.com>
-Date: Mon, 1 May 2017 14:45:04 +0200
-
-This patch adds documentation for Device-Tree bindings for the
-syscon present in allwinner devices.
-
-Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
----
- .../devicetree/bindings/misc/allwinner,syscon.txt | 19 +++++++++++++++++++
- 1 file changed, 19 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/misc/allwinner,syscon.txt
-
-diff --git a/Documentation/devicetree/bindings/misc/allwinner,syscon.txt b/Documentation/devicetree/bindings/misc/allwinner,syscon.txt
-new file mode 100644
-index 0000000..cb57691
---- /dev/null
-+++ b/Documentation/devicetree/bindings/misc/allwinner,syscon.txt
-@@ -0,0 +1,19 @@
-+* Allwinner sun8i system controller
-+
-+This file describes the bindings for the system controller present in
-+Allwinner SoC H3, A83T and A64.
-+The principal function of this syscon is to control EMAC PHY choice and
-+config.
-+
-+Required properties for the system controller:
-+- reg: address and length of the register for the device.
-+- compatible: should be "syscon" and one of the following string:
-+ "allwinner,sun8i-h3-system-controller"
-+ "allwinner,sun50i-a64-system-controller"
-+ "allwinner,sun8i-a83t-system-controller"
-+
-+Example:
-+syscon: syscon@1c00000 {
-+ compatible = "allwinner,sun8i-h3-system-controller", "syscon";
-+ reg = <0x01c00000 0x1000>;
-+};
-
-From patchwork Mon May 1 12:45:05 2017
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v5,05/20] net: stmmac: Add dwmac-sun8i
-From: Corentin LABBE <clabbe.montjoie@gmail.com>
-X-Patchwork-Id: 9706473
-Message-Id: <20170501124520.3769-6-clabbe.montjoie@gmail.com>
-To: robh+dt@kernel.org, mark.rutland@arm.com,
- maxime.ripard@free-electrons.com, wens@csie.org,
- linux@armlinux.org.uk, catalin.marinas@arm.com,
- will.deacon@arm.com, peppe.cavallaro@st.com, alexandre.torgue@st.com
-Cc: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
- netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Corentin Labbe <clabbe.montjoie@gmail.com>
-Date: Mon, 1 May 2017 14:45:05 +0200
-
-The dwmac-sun8i is a heavy hacked version of stmmac hardware by
-allwinner.
-In fact the only common part is the descriptor management and the first
-register function.
-
-Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
----
- drivers/net/ethernet/stmicro/stmmac/Kconfig | 11 +
- drivers/net/ethernet/stmicro/stmmac/Makefile | 1 +
- drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c | 973 +++++++++++++++++++++
- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 29 +
- .../net/ethernet/stmicro/stmmac/stmmac_platform.c | 9 +-
- include/linux/stmmac.h | 1 +
- 6 files changed, 1022 insertions(+), 2 deletions(-)
- create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
-
-diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-index cfbe363..85c0e41 100644
---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
-+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-@@ -145,6 +145,17 @@ config DWMAC_SUNXI
- This selects Allwinner SoC glue layer support for the
- stmmac device driver. This driver is used for A20/A31
- GMAC ethernet controller.
-+
-+config DWMAC_SUN8I
-+ tristate "Allwinner sun8i GMAC support"
-+ default ARCH_SUNXI
-+ depends on OF && (ARCH_SUNXI || COMPILE_TEST)
-+ ---help---
-+ Support for Allwinner H3 A83T A64 EMAC ethernet controllers.
-+
-+ This selects Allwinner SoC glue layer support for the
-+ stmmac device driver. This driver is used for H3/A83T/A64
-+ EMAC ethernet controller.
- endif
-
- config STMMAC_PCI
-diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
-index 700c603..fd4937a 100644
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -16,6 +16,7 @@ obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o
- obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
- obj-$(CONFIG_DWMAC_STM32) += dwmac-stm32.o
- obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
-+obj-$(CONFIG_DWMAC_SUN8I) += dwmac-sun8i.o
- obj-$(CONFIG_DWMAC_DWC_QOS_ETH) += dwmac-dwc-qos-eth.o
- obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
- stmmac-platform-objs:= stmmac_platform.o
-diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
-new file mode 100644
-index 0000000..66eb980
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
-@@ -0,0 +1,973 @@
-+/*
-+ * dwmac-sun8i.c - Allwinner sun8i DWMAC specific glue layer
-+ *
-+ * Copyright (C) 2017 Corentin Labbe <clabbe.montjoie@gmail.com>
-+ *
-+ * 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.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/io.h>
-+#include <linux/iopoll.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/of_device.h>
-+#include <linux/of_mdio.h>
-+#include <linux/of_net.h>
-+#include <linux/phy.h>
-+#include <linux/platform_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/regmap.h>
-+#include <linux/stmmac.h>
-+
-+#include "stmmac.h"
-+#include "stmmac_platform.h"
-+
-+/* General notes on dwmac-sun8i:
-+ * Locking: no locking is necessary in this file because all necessary locking
-+ * is done in the "stmmac files"
-+ */
-+
-+/* struct emac_variant - Descrive dwmac-sun8i hardware variant
-+ * @default_syscon_value: The default value of the EMAC register in syscon
-+ * This value is used for disabling properly EMAC
-+ * and used as a good starting value in case of the
-+ * boot process(uboot) leave some stuff.
-+ * @internal_phy: Does the MAC embed an internal PHY
-+ * @support_mii: Does the MAC handle MII
-+ * @support_rmii: Does the MAC handle RMII
-+ * @support_rgmii: Does the MAC handle RGMII
-+ */
-+struct emac_variant {
-+ u32 default_syscon_value;
-+ int internal_phy;
-+ bool support_mii;
-+ bool support_rmii;
-+ bool support_rgmii;
-+};
-+
-+/* struct sunxi_priv_data - hold all sunxi private data
-+ * @tx_clk: reference to MAC TX clock
-+ * @ephy_clk: reference to the optional EPHY clock for the internal PHY
-+ * @regulator: reference to the optional regulator
-+ * @rst_ephy: reference to the optional EPHY reset for the internal PHY
-+ * @variant: reference to the current board variant
-+ * @regmap: regmap for using the syscon
-+ * @use_internal_phy: Does the current PHY choice imply using the internal PHY
-+ */
-+struct sunxi_priv_data {
-+ struct clk *tx_clk;
-+ struct clk *ephy_clk;
-+ struct regulator *regulator;
-+ struct reset_control *rst_ephy;
-+ const struct emac_variant *variant;
-+ struct regmap *regmap;
-+ bool use_internal_phy;
-+};
-+
-+static const struct emac_variant emac_variant_h3 = {
-+ .default_syscon_value = 0x58000,
-+ .internal_phy = PHY_INTERFACE_MODE_MII,
-+ .support_mii = true,
-+ .support_rmii = true,
-+ .support_rgmii = true
-+};
-+
-+static const struct emac_variant emac_variant_a83t = {
-+ .default_syscon_value = 0,
-+ .internal_phy = 0,
-+ .support_mii = true,
-+ .support_rgmii = true
-+};
-+
-+static const struct emac_variant emac_variant_a64 = {
-+ .default_syscon_value = 0,
-+ .internal_phy = 0,
-+ .support_mii = true,
-+ .support_rmii = true,
-+ .support_rgmii = true
-+};
-+
-+#define EMAC_BASIC_CTL0 0x00
-+#define EMAC_BASIC_CTL1 0x04
-+#define EMAC_INT_STA 0x08
-+#define EMAC_INT_EN 0x0C
-+#define EMAC_TX_CTL0 0x10
-+#define EMAC_TX_CTL1 0x14
-+#define EMAC_TX_FLOW_CTL 0x1C
-+#define EMAC_TX_DESC_LIST 0x20
-+#define EMAC_RX_CTL0 0x24
-+#define EMAC_RX_CTL1 0x28
-+#define EMAC_RX_DESC_LIST 0x34
-+#define EMAC_RX_FRM_FLT 0x38
-+#define EMAC_MDIO_CMD 0x48
-+#define EMAC_MDIO_DATA 0x4C
-+#define EMAC_MACADDR_HI(reg) (0x50 + (reg) * 8)
-+#define EMAC_MACADDR_LO(reg) (0x54 + (reg) * 8)
-+#define EMAC_TX_DMA_STA 0xB0
-+#define EMAC_TX_CUR_DESC 0xB4
-+#define EMAC_TX_CUR_BUF 0xB8
-+#define EMAC_RX_DMA_STA 0xC0
-+#define EMAC_RX_CUR_DESC 0xC4
-+#define EMAC_RX_CUR_BUF 0xC8
-+
-+/* Use in EMAC_BASIC_CTL1 */
-+#define EMAC_BURSTLEN_SHIFT 24
-+
-+/* Used in EMAC_RX_FRM_FLT */
-+#define EMAC_FRM_FLT_RXALL BIT(0)
-+#define EMAC_FRM_FLT_CTL BIT(13)
-+#define EMAC_FRM_FLT_MULTICAST BIT(16)
-+
-+/* Used in RX_CTL1*/
-+#define EMAC_RX_MD BIT(1)
-+#define EMAC_RX_TH_MASK GENMASK(4, 5)
-+#define EMAC_RX_TH_32 0
-+#define EMAC_RX_TH_64 (0x1 << 4)
-+#define EMAC_RX_TH_96 (0x2 << 4)
-+#define EMAC_RX_TH_128 (0x3 << 4)
-+#define EMAC_RX_DMA_EN BIT(30)
-+#define EMAC_RX_DMA_START BIT(31)
-+
-+/* Used in TX_CTL1*/
-+#define EMAC_TX_MD BIT(1)
-+#define EMAC_TX_NEXT_FRM BIT(2)
-+#define EMAC_TX_TH_MASK GENMASK(8, 10)
-+#define EMAC_TX_TH_64 0
-+#define EMAC_TX_TH_128 (0x1 << 8)
-+#define EMAC_TX_TH_192 (0x2 << 8)
-+#define EMAC_TX_TH_256 (0x3 << 8)
-+#define EMAC_TX_DMA_EN BIT(30)
-+#define EMAC_TX_DMA_START BIT(31)
-+
-+/* Used in RX_CTL0 */
-+#define EMAC_RX_RECEIVER_EN BIT(31)
-+#define EMAC_RX_DO_CRC BIT(27)
-+#define EMAC_RX_FLOW_CTL_EN BIT(16)
-+
-+/* Used in TX_CTL0 */
-+#define EMAC_TX_TRANSMITTER_EN BIT(31)
-+
-+/* Used in EMAC_TX_FLOW_CTL */
-+#define EMAC_TX_FLOW_CTL_EN BIT(0)
-+
-+/* Used in EMAC_INT_STA */
-+#define EMAC_TX_INT BIT(0)
-+#define EMAC_TX_DMA_STOP_INT BIT(1)
-+#define EMAC_TX_BUF_UA_INT BIT(2)
-+#define EMAC_TX_TIMEOUT_INT BIT(3)
-+#define EMAC_TX_UNDERFLOW_INT BIT(4)
-+#define EMAC_TX_EARLY_INT BIT(5)
-+#define EMAC_RX_INT BIT(8)
-+#define EMAC_RX_BUF_UA_INT BIT(9)
-+#define EMAC_RX_DMA_STOP_INT BIT(10)
-+#define EMAC_RX_TIMEOUT_INT BIT(11)
-+#define EMAC_RX_OVERFLOW_INT BIT(12)
-+#define EMAC_RX_EARLY_INT BIT(13)
-+#define EMAC_RGMII_STA_INT BIT(16)
-+
-+#define MAC_ADDR_TYPE_DST BIT(31)
-+
-+/* H3 specific bits for EPHY */
-+#define H3_EPHY_ADDR_SHIFT 20
-+#define H3_EPHY_LED_POL BIT(17) /* 1: active low, 0: active high */
-+#define H3_EPHY_SHUTDOWN BIT(16) /* 1: shutdown, 0: power up */
-+#define H3_EPHY_SELECT BIT(15) /* 1: internal PHY, 0: external PHY */
-+
-+/* H3/A64 specific bits */
-+#define SYSCON_RMII_EN BIT(13) /* 1: enable RMII (overrides EPIT) */
-+
-+/* Generic system control EMAC_CLK bits */
-+#define SYSCON_ETXDC_MASK GENMASK(2, 0)
-+#define SYSCON_ETXDC_SHIFT 10
-+#define SYSCON_ERXDC_MASK GENMASK(4, 0)
-+#define SYSCON_ERXDC_SHIFT 5
-+/* EMAC PHY Interface Type */
-+#define SYSCON_EPIT BIT(2) /* 1: RGMII, 0: MII */
-+#define SYSCON_ETCS_MASK GENMASK(1, 0)
-+#define SYSCON_ETCS_MII 0x0
-+#define SYSCON_ETCS_EXT_GMII 0x1
-+#define SYSCON_ETCS_INT_GMII 0x2
-+#define SYSCON_EMAC_REG 0x30
-+
-+/* sun8i_dwmac_dma_reset() - reset the EMAC
-+ * Called from stmmac via stmmac_dma_ops->reset
-+ */
-+static int sun8i_dwmac_dma_reset(void __iomem *ioaddr)
-+{
-+ writel(0, ioaddr + EMAC_RX_CTL1);
-+ writel(0, ioaddr + EMAC_TX_CTL1);
-+ writel(0, ioaddr + EMAC_RX_FRM_FLT);
-+ writel(0, ioaddr + EMAC_RX_DESC_LIST);
-+ writel(0, ioaddr + EMAC_TX_DESC_LIST);
-+ writel(0, ioaddr + EMAC_INT_EN);
-+ writel(0x1FFFFFF, ioaddr + EMAC_INT_STA);
-+ return 0;
-+}
-+
-+/* sun8i_dwmac_dma_init() - initialize the EMAC
-+ * Called from stmmac via stmmac_dma_ops->init
-+ */
-+static void sun8i_dwmac_dma_init(void __iomem *ioaddr,
-+ struct stmmac_dma_cfg *dma_cfg,
-+ u32 dma_tx, u32 dma_rx, int atds)
-+{
-+ /* Write TX and RX descriptors address */
-+ writel(dma_rx, ioaddr + EMAC_RX_DESC_LIST);
-+ writel(dma_tx, ioaddr + EMAC_TX_DESC_LIST);
-+
-+ writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN);
-+ writel(0x1FFFFFF, ioaddr + EMAC_INT_STA);
-+}
-+
-+/* sun8i_dwmac_dump_regs() - Dump EMAC address space
-+ * Called from stmmac_dma_ops->dump_regs
-+ * Used for ethtool
-+ */
-+static void sun8i_dwmac_dump_regs(void __iomem *ioaddr, u32 *reg_space)
-+{
-+ int i;
-+
-+ for (i = 0; i < 0xC8; i += 4) {
-+ if (i == 0x32 || i == 0x3C)
-+ continue;
-+ reg_space[i / 4] = readl(ioaddr + i);
-+ }
-+}
-+
-+/* sun8i_dwmac_dump_mac_regs() - Dump EMAC address space
-+ * Called from stmmac_ops->dump_regs
-+ * Used for ethtool
-+ */
-+static void sun8i_dwmac_dump_mac_regs(struct mac_device_info *hw,
-+ u32 *reg_space)
-+{
-+ int i;
-+ void __iomem *ioaddr = hw->pcsr;
-+
-+ for (i = 0; i < 0xC8; i += 4) {
-+ if (i == 0x32 || i == 0x3C)
-+ continue;
-+ reg_space[i / 4] = readl(ioaddr + i);
-+ }
-+}
-+
-+static void sun8i_dwmac_enable_dma_irq(void __iomem *ioaddr, u32 chan)
-+{
-+ writel(EMAC_RX_INT | EMAC_TX_INT, ioaddr + EMAC_INT_EN);
-+}
-+
-+static void sun8i_dwmac_disable_dma_irq(void __iomem *ioaddr, u32 chan)
-+{
-+ writel(0, ioaddr + EMAC_INT_EN);
-+}
-+
-+static void sun8i_dwmac_dma_start_tx(void __iomem *ioaddr, u32 chan)
-+{
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_TX_CTL1);
-+ v |= EMAC_TX_DMA_START;
-+ v |= EMAC_TX_DMA_EN;
-+ writel(v, ioaddr + EMAC_TX_CTL1);
-+}
-+
-+static void sun8i_dwmac_enable_dma_transmission(void __iomem *ioaddr)
-+{
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_TX_CTL1);
-+ v |= EMAC_TX_DMA_START;
-+ v |= EMAC_TX_DMA_EN;
-+ writel(v, ioaddr + EMAC_TX_CTL1);
-+}
-+
-+static void sun8i_dwmac_dma_stop_tx(void __iomem *ioaddr, u32 chan)
-+{
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_TX_CTL1);
-+ v &= ~EMAC_TX_DMA_EN;
-+ writel(v, ioaddr + EMAC_TX_CTL1);
-+}
-+
-+static void sun8i_dwmac_dma_start_rx(void __iomem *ioaddr, u32 chan)
-+{
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_RX_CTL1);
-+ v |= EMAC_RX_DMA_START;
-+ v |= EMAC_RX_DMA_EN;
-+ writel(v, ioaddr + EMAC_RX_CTL1);
-+}
-+
-+static void sun8i_dwmac_dma_stop_rx(void __iomem *ioaddr, u32 chan)
-+{
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_RX_CTL1);
-+ v &= ~EMAC_RX_DMA_EN;
-+ writel(v, ioaddr + EMAC_RX_CTL1);
-+}
-+
-+static int sun8i_dwmac_dma_interrupt(void __iomem *ioaddr,
-+ struct stmmac_extra_stats *x, u32 chan)
-+{
-+ u32 v;
-+ int ret = 0;
-+
-+ v = readl(ioaddr + EMAC_INT_STA);
-+
-+ if (v & EMAC_TX_INT) {
-+ ret |= handle_tx;
-+ x->tx_normal_irq_n++;
-+ }
-+
-+ if (v & EMAC_TX_DMA_STOP_INT)
-+ x->tx_process_stopped_irq++;
-+
-+ if (v & EMAC_TX_BUF_UA_INT)
-+ x->tx_process_stopped_irq++;
-+
-+ if (v & EMAC_TX_TIMEOUT_INT)
-+ ret |= tx_hard_error;
-+
-+ if (v & EMAC_TX_UNDERFLOW_INT) {
-+ ret |= tx_hard_error;
-+ x->tx_undeflow_irq++;
-+ }
-+
-+ if (v & EMAC_TX_EARLY_INT)
-+ x->tx_early_irq++;
-+
-+ if (v & EMAC_RX_INT) {
-+ ret |= handle_rx;
-+ x->rx_normal_irq_n++;
-+ }
-+
-+ if (v & EMAC_RX_BUF_UA_INT)
-+ x->rx_buf_unav_irq++;
-+
-+ if (v & EMAC_RX_DMA_STOP_INT)
-+ x->rx_process_stopped_irq++;
-+
-+ if (v & EMAC_RX_TIMEOUT_INT)
-+ ret |= tx_hard_error;
-+
-+ if (v & EMAC_RX_OVERFLOW_INT) {
-+ ret |= tx_hard_error;
-+ x->rx_overflow_irq++;
-+ }
-+
-+ if (v & EMAC_RX_EARLY_INT)
-+ x->rx_early_irq++;
-+
-+ if (v & EMAC_RGMII_STA_INT)
-+ x->irq_rgmii_n++;
-+
-+ writel(v, ioaddr + EMAC_INT_STA);
-+
-+ return ret;
-+}
-+
-+static void sun8i_dwmac_dma_operation_mode(void __iomem *ioaddr, int txmode,
-+ int rxmode, int rxfifosz)
-+{
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_TX_CTL1);
-+ if (txmode == SF_DMA_MODE) {
-+ v |= EMAC_TX_MD;
-+ /* Undocumented bit (called TX_NEXT_FRM in BSP), the original
-+ * comment is
-+ * "Operating on second frame increase the performance
-+ * especially when transmit store-and-forward is used."
-+ */
-+ v |= EMAC_TX_NEXT_FRM;
-+ } else {
-+ v &= ~EMAC_TX_MD;
-+ v &= ~EMAC_TX_TH_MASK;
-+ if (txmode < 64)
-+ v |= EMAC_TX_TH_64;
-+ else if (txmode < 128)
-+ v |= EMAC_TX_TH_128;
-+ else if (txmode < 192)
-+ v |= EMAC_TX_TH_192;
-+ else if (txmode < 256)
-+ v |= EMAC_TX_TH_256;
-+ }
-+ writel(v, ioaddr + EMAC_TX_CTL1);
-+
-+ v = readl(ioaddr + EMAC_RX_CTL1);
-+ if (rxmode == SF_DMA_MODE) {
-+ v |= EMAC_RX_MD;
-+ } else {
-+ v &= ~EMAC_RX_MD;
-+ v &= ~EMAC_RX_TH_MASK;
-+ if (rxmode < 32)
-+ v |= EMAC_RX_TH_32;
-+ else if (rxmode < 64)
-+ v |= EMAC_RX_TH_64;
-+ else if (rxmode < 96)
-+ v |= EMAC_RX_TH_96;
-+ else if (rxmode < 128)
-+ v |= EMAC_RX_TH_128;
-+ }
-+ writel(v, ioaddr + EMAC_RX_CTL1);
-+}
-+
-+static const struct stmmac_dma_ops sun8i_dwmac_dma_ops = {
-+ .reset = sun8i_dwmac_dma_reset,
-+ .init = sun8i_dwmac_dma_init,
-+ .dump_regs = sun8i_dwmac_dump_regs,
-+ .dma_mode = sun8i_dwmac_dma_operation_mode,
-+ .enable_dma_transmission = sun8i_dwmac_enable_dma_transmission,
-+ .enable_dma_irq = sun8i_dwmac_enable_dma_irq,
-+ .disable_dma_irq = sun8i_dwmac_disable_dma_irq,
-+ .start_tx = sun8i_dwmac_dma_start_tx,
-+ .stop_tx = sun8i_dwmac_dma_stop_tx,
-+ .start_rx = sun8i_dwmac_dma_start_rx,
-+ .stop_rx = sun8i_dwmac_dma_stop_rx,
-+ .dma_interrupt = sun8i_dwmac_dma_interrupt,
-+};
-+
-+static int sun8i_dwmac_init(struct platform_device *pdev, void *priv)
-+{
-+ struct sunxi_priv_data *gmac = priv;
-+ int ret;
-+
-+ if (gmac->regulator) {
-+ ret = regulator_enable(gmac->regulator);
-+ if (ret) {
-+ dev_err(&pdev->dev, "Fail to enable regulator\n");
-+ return ret;
-+ }
-+ }
-+
-+ ret = clk_prepare_enable(gmac->tx_clk);
-+ if (ret) {
-+ if (gmac->regulator)
-+ regulator_disable(gmac->regulator);
-+ dev_err(&pdev->dev, "Could not enable AHB clock\n");
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static void sun8i_dwmac_core_init(struct mac_device_info *hw, int mtu)
-+{
-+ void __iomem *ioaddr = hw->pcsr;
-+ u32 v;
-+
-+ v = (8 << EMAC_BURSTLEN_SHIFT); /* burst len */
-+ writel(v, ioaddr + EMAC_BASIC_CTL1);
-+}
-+
-+static void sun8i_dwmac_set_mac(void __iomem *ioaddr, bool enable)
-+{
-+ u32 t, r;
-+
-+ t = readl(ioaddr + EMAC_TX_CTL0);
-+ r = readl(ioaddr + EMAC_RX_CTL0);
-+ if (enable) {
-+ t |= EMAC_TX_TRANSMITTER_EN;
-+ r |= EMAC_RX_RECEIVER_EN;
-+ } else {
-+ t &= ~EMAC_TX_TRANSMITTER_EN;
-+ r &= ~EMAC_RX_RECEIVER_EN;
-+ }
-+ writel(t, ioaddr + EMAC_TX_CTL0);
-+ writel(r, ioaddr + EMAC_RX_CTL0);
-+}
-+
-+/* Set MAC address at slot reg_n
-+ * All slot > 0 need to be enabled with MAC_ADDR_TYPE_DST
-+ * If addr is NULL, clear the slot
-+ */
-+static void sun8i_dwmac_set_umac_addr(struct mac_device_info *hw,
-+ unsigned char *addr,
-+ unsigned int reg_n)
-+{
-+ void __iomem *ioaddr = hw->pcsr;
-+ u32 v;
-+
-+ if (!addr) {
-+ writel(0, ioaddr + EMAC_MACADDR_HI(reg_n));
-+ return;
-+ }
-+
-+ stmmac_set_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n),
-+ EMAC_MACADDR_LO(reg_n));
-+ if (reg_n > 0) {
-+ v = readl(ioaddr + EMAC_MACADDR_HI(reg_n));
-+ v |= MAC_ADDR_TYPE_DST;
-+ writel(v, ioaddr + EMAC_MACADDR_HI(reg_n));
-+ }
-+}
-+
-+static void sun8i_dwmac_get_umac_addr(struct mac_device_info *hw,
-+ unsigned char *addr,
-+ unsigned int reg_n)
-+{
-+ void __iomem *ioaddr = hw->pcsr;
-+
-+ stmmac_get_mac_addr(ioaddr, addr, EMAC_MACADDR_HI(reg_n),
-+ EMAC_MACADDR_LO(reg_n));
-+}
-+
-+/* caution this function must return non 0 to work */
-+static int sun8i_dwmac_rx_ipc_enable(struct mac_device_info *hw)
-+{
-+ void __iomem *ioaddr = hw->pcsr;
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_RX_CTL0);
-+ v |= EMAC_RX_DO_CRC;
-+ writel(v, ioaddr + EMAC_RX_CTL0);
-+
-+ return 1;
-+}
-+
-+static void sun8i_dwmac_set_filter(struct mac_device_info *hw,
-+ struct net_device *dev)
-+{
-+ void __iomem *ioaddr = hw->pcsr;
-+ u32 v;
-+ int i = 1;
-+ struct netdev_hw_addr *ha;
-+ int macaddrs = netdev_uc_count(dev) + netdev_mc_count(dev) + 1;
-+
-+ v = EMAC_FRM_FLT_CTL;
-+
-+ if (dev->flags & IFF_PROMISC) {
-+ v = EMAC_FRM_FLT_RXALL;
-+ } else if (dev->flags & IFF_ALLMULTI) {
-+ v |= EMAC_FRM_FLT_MULTICAST;
-+ } else if (macaddrs <= hw->unicast_filter_entries) {
-+ if (!netdev_mc_empty(dev)) {
-+ netdev_for_each_mc_addr(ha, dev) {
-+ sun8i_dwmac_set_umac_addr(hw, ha->addr, i);
-+ i++;
-+ }
-+ }
-+ if (!netdev_uc_empty(dev)) {
-+ netdev_for_each_uc_addr(ha, dev) {
-+ sun8i_dwmac_set_umac_addr(hw, ha->addr, i);
-+ i++;
-+ }
-+ }
-+ } else {
-+ netdev_info(dev, "Too many address, switching to promiscuous\n");
-+ v = EMAC_FRM_FLT_RXALL;
-+ }
-+
-+ /* Disable unused address filter slots */
-+ while (i < hw->unicast_filter_entries)
-+ sun8i_dwmac_set_umac_addr(hw, NULL, i++);
-+
-+ writel(v, ioaddr + EMAC_RX_FRM_FLT);
-+}
-+
-+static void sun8i_dwmac_flow_ctrl(struct mac_device_info *hw,
-+ unsigned int duplex, unsigned int fc,
-+ unsigned int pause_time, u32 tx_cnt)
-+{
-+ void __iomem *ioaddr = hw->pcsr;
-+ u32 v;
-+
-+ v = readl(ioaddr + EMAC_RX_CTL0);
-+ if (fc == FLOW_AUTO)
-+ v |= EMAC_RX_FLOW_CTL_EN;
-+ else
-+ v &= ~EMAC_RX_FLOW_CTL_EN;
-+ writel(v, ioaddr + EMAC_RX_CTL0);
-+
-+ v = readl(ioaddr + EMAC_TX_FLOW_CTL);
-+ if (fc == FLOW_AUTO)
-+ v |= EMAC_TX_FLOW_CTL_EN;
-+ else
-+ v &= ~EMAC_TX_FLOW_CTL_EN;
-+ writel(v, ioaddr + EMAC_TX_FLOW_CTL);
-+}
-+
-+static int sun8i_dwmac_reset(struct stmmac_priv *priv)
-+{
-+ u32 v;
-+ int err;
-+
-+ v = readl(priv->ioaddr + EMAC_BASIC_CTL1);
-+ writel(v | 0x01, priv->ioaddr + EMAC_BASIC_CTL1);
-+
-+ err = readl_poll_timeout(priv->ioaddr + EMAC_BASIC_CTL1, v,
-+ !(v & 0x01), 100, 10000);
-+
-+ if (err) {
-+ dev_err(priv->device, "EMAC reset timeout\n");
-+ return -EFAULT;
-+ }
-+ return 0;
-+}
-+
-+static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
-+{
-+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
-+ struct device_node *node = priv->device->of_node;
-+ int ret;
-+ u32 reg, val;
-+
-+ regmap_read(gmac->regmap, SYSCON_EMAC_REG, &val);
-+ reg = gmac->variant->default_syscon_value;
-+ if (reg != val)
-+ dev_warn(priv->device,
-+ "Current syscon value is not the default %x (expect %x)\n",
-+ val, reg);
-+
-+ if (gmac->variant->internal_phy) {
-+ if (!gmac->use_internal_phy) {
-+ /* switch to external PHY interface */
-+ reg &= ~H3_EPHY_SELECT;
-+ } else {
-+ reg |= H3_EPHY_SELECT;
-+ reg &= ~H3_EPHY_SHUTDOWN;
-+ dev_dbg(priv->device, "Select internal_phy %x\n", reg);
-+
-+ if (of_property_read_bool(priv->plat->phy_node,
-+ "allwinner,leds-active-low"))
-+ reg |= H3_EPHY_LED_POL;
-+ else
-+ reg &= ~H3_EPHY_LED_POL;
-+
-+ ret = of_mdio_parse_addr(priv->device,
-+ priv->plat->phy_node);
-+ if (ret < 0) {
-+ dev_err(priv->device, "Could not parse MDIO addr\n");
-+ return ret;
-+ }
-+ /* of_mdio_parse_addr returns a valid (0 ~ 31) PHY
-+ * address. No need to mask it again.
-+ */
-+ reg |= ret << H3_EPHY_ADDR_SHIFT;
-+ }
-+ }
-+
-+ if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
-+ if (val % 100) {
-+ dev_err(priv->device, "tx-delay must be a multiple of 100\n");
-+ return -EINVAL;
-+ }
-+ val /= 100;
-+ dev_dbg(priv->device, "set tx-delay to %x\n", val);
-+ if (val <= SYSCON_ETXDC_MASK) {
-+ reg &= ~(SYSCON_ETXDC_MASK << SYSCON_ETXDC_SHIFT);
-+ reg |= (val << SYSCON_ETXDC_SHIFT);
-+ } else {
-+ dev_err(priv->device, "Invalid TX clock delay: %d\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ if (!of_property_read_u32(node, "allwinner,rx-delay-ps", &val)) {
-+ if (val % 100) {
-+ dev_err(priv->device, "rx-delay must be a multiple of 100\n");
-+ return -EINVAL;
-+ }
-+ val /= 100;
-+ dev_dbg(priv->device, "set rx-delay to %x\n", val);
-+ if (val <= SYSCON_ERXDC_MASK) {
-+ reg &= ~(SYSCON_ERXDC_MASK << SYSCON_ERXDC_SHIFT);
-+ reg |= (val << SYSCON_ERXDC_SHIFT);
-+ } else {
-+ dev_err(priv->device, "Invalid RX clock delay: %d\n",
-+ val);
-+ return -EINVAL;
-+ }
-+ }
-+
-+ /* Clear interface mode bits */
-+ reg &= ~(SYSCON_ETCS_MASK | SYSCON_EPIT);
-+ if (gmac->variant->support_rmii)
-+ reg &= ~SYSCON_RMII_EN;
-+
-+ switch (priv->plat->interface) {
-+ case PHY_INTERFACE_MODE_MII:
-+ /* default */
-+ break;
-+ case PHY_INTERFACE_MODE_RGMII:
-+ reg |= SYSCON_EPIT | SYSCON_ETCS_INT_GMII;
-+ break;
-+ case PHY_INTERFACE_MODE_RMII:
-+ reg |= SYSCON_RMII_EN | SYSCON_ETCS_EXT_GMII;
-+ break;
-+ default:
-+ dev_err(priv->device, "Unsupported interface mode: %s",
-+ phy_modes(priv->plat->interface));
-+ return -EINVAL;
-+ }
-+
-+ regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg);
-+
-+ return 0;
-+}
-+
-+static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac)
-+{
-+ u32 reg = gmac->variant->default_syscon_value;
-+
-+ regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg);
-+}
-+
-+static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
-+{
-+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
-+ int ret;
-+
-+ if (!gmac->use_internal_phy)
-+ return 0;
-+
-+ ret = clk_prepare_enable(gmac->ephy_clk);
-+ if (ret) {
-+ dev_err(priv->device, "Cannot enable ephy\n");
-+ return ret;
-+ }
-+
-+ ret = reset_control_deassert(gmac->rst_ephy);
-+ if (ret) {
-+ dev_err(priv->device, "Cannot deassert ephy\n");
-+ clk_disable_unprepare(gmac->ephy_clk);
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
-+static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
-+{
-+ if (!gmac->use_internal_phy)
-+ return 0;
-+
-+ clk_disable_unprepare(gmac->ephy_clk);
-+ reset_control_assert(gmac->rst_ephy);
-+ return 0;
-+}
-+
-+static int sun8i_power_phy(struct stmmac_priv *priv)
-+{
-+ struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
-+ int ret;
-+
-+ ret = sun8i_dwmac_power_internal_phy(priv);
-+ if (ret)
-+ return ret;
-+
-+ ret = sun8i_dwmac_set_syscon(priv);
-+ if (ret)
-+ goto error_phy;
-+
-+ ret = sun8i_dwmac_reset(priv);
-+ if (ret)
-+ goto error_phy;
-+ return 0;
-+
-+error_phy:
-+ sun8i_dwmac_unset_syscon(gmac);
-+ sun8i_dwmac_unpower_internal_phy(gmac);
-+ return ret;
-+}
-+
-+static void sun8i_unpower_phy(struct sunxi_priv_data *gmac)
-+{
-+ sun8i_dwmac_unset_syscon(gmac);
-+ sun8i_dwmac_unpower_internal_phy(gmac);
-+}
-+
-+static void sun8i_dwmac_exit(struct platform_device *pdev, void *priv)
-+{
-+ struct sunxi_priv_data *gmac = priv;
-+
-+ sun8i_unpower_phy(gmac);
-+
-+ clk_disable_unprepare(gmac->tx_clk);
-+
-+ if (gmac->regulator)
-+ regulator_disable(gmac->regulator);
-+}
-+
-+static const struct stmmac_ops sun8i_dwmac_ops = {
-+ .core_init = sun8i_dwmac_core_init,
-+ .set_mac = sun8i_dwmac_set_mac,
-+ .dump_regs = sun8i_dwmac_dump_mac_regs,
-+ .rx_ipc = sun8i_dwmac_rx_ipc_enable,
-+ .set_filter = sun8i_dwmac_set_filter,
-+ .flow_ctrl = sun8i_dwmac_flow_ctrl,
-+ .set_umac_addr = sun8i_dwmac_set_umac_addr,
-+ .get_umac_addr = sun8i_dwmac_get_umac_addr,
-+};
-+
-+static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
-+{
-+ struct mac_device_info *mac;
-+ struct stmmac_priv *priv = ppriv;
-+ int ret;
-+
-+ mac = devm_kzalloc(priv->device, sizeof(*mac), GFP_KERNEL);
-+ if (!mac)
-+ return NULL;
-+
-+ ret = sun8i_power_phy(priv);
-+ if (ret)
-+ return NULL;
-+
-+ mac->pcsr = priv->ioaddr;
-+ mac->mac = &sun8i_dwmac_ops;
-+ mac->dma = &sun8i_dwmac_dma_ops;
-+
-+ mac->link.port = 0;
-+ mac->link.duplex = BIT(0);
-+ mac->link.speed = 1;
-+ mac->mii.addr = EMAC_MDIO_CMD;
-+ mac->mii.data = EMAC_MDIO_DATA;
-+ mac->mii.reg_shift = 4;
-+ mac->mii.reg_mask = GENMASK(8, 4);
-+ mac->mii.addr_shift = 12;
-+ mac->mii.addr_mask = GENMASK(16, 12);
-+ mac->mii.clk_csr_shift = 20;
-+ mac->mii.clk_csr_mask = GENMASK(22, 20);
-+ mac->unicast_filter_entries = 8;
-+
-+ /* Synopsys Id is not available */
-+ priv->synopsys_id = 0;
-+
-+ return mac;
-+}
-+
-+static int sun8i_dwmac_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->variant = of_device_get_match_data(&pdev->dev);
-+ if (!gmac->variant) {
-+ dev_err(&pdev->dev, "Missing dwmac-sun8i variant\n");
-+ return -EINVAL;
-+ }
-+
-+ gmac->tx_clk = devm_clk_get(dev, "stmmaceth");
-+ 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;
-+ }
-+
-+ gmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
-+ "syscon");
-+ if (IS_ERR(gmac->regmap)) {
-+ ret = PTR_ERR(gmac->regmap);
-+ dev_err(&pdev->dev, "Unable to map syscon: %d\n", ret);
-+ return ret;
-+ }
-+
-+ plat_dat->interface = of_get_phy_mode(dev->of_node);
-+ if (plat_dat->interface == gmac->variant->internal_phy) {
-+ dev_info(&pdev->dev, "Will use internal PHY\n");
-+ gmac->use_internal_phy = true;
-+ gmac->ephy_clk = of_clk_get(plat_dat->phy_node, 0);
-+ if (IS_ERR(gmac->ephy_clk)) {
-+ ret = PTR_ERR(gmac->ephy_clk);
-+ dev_err(&pdev->dev, "Cannot get EPHY clock: %d\n", ret);
-+ return -EINVAL;
-+ }
-+
-+ gmac->rst_ephy = of_reset_control_get(plat_dat->phy_node, NULL);
-+ if (IS_ERR(gmac->rst_ephy)) {
-+ ret = PTR_ERR(gmac->rst_ephy);
-+ if (ret == -EPROBE_DEFER)
-+ return ret;
-+ dev_err(&pdev->dev, "No EPHY reset control found %d\n",
-+ ret);
-+ return -EINVAL;
-+ }
-+ } else {
-+ dev_info(&pdev->dev, "Will use external PHY\n");
-+ gmac->use_internal_phy = false;
-+ }
-+
-+ /* platform data specifying hardware features and callbacks.
-+ * hardware features were copied from Allwinner drivers.
-+ */
-+ plat_dat->rx_coe = STMMAC_RX_COE_TYPE2;
-+ plat_dat->tx_coe = 1;
-+ plat_dat->has_sun8i = true;
-+ plat_dat->bsp_priv = gmac;
-+ plat_dat->init = sun8i_dwmac_init;
-+ plat_dat->exit = sun8i_dwmac_exit;
-+ plat_dat->setup = sun8i_dwmac_setup;
-+
-+ ret = sun8i_dwmac_init(pdev, plat_dat->bsp_priv);
-+ if (ret)
-+ return ret;
-+
-+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+ if (ret)
-+ sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
-+
-+ return ret;
-+}
-+
-+static const struct of_device_id sun8i_dwmac_match[] = {
-+ { .compatible = "allwinner,sun8i-h3-emac",
-+ .data = &emac_variant_h3 },
-+ { .compatible = "allwinner,sun8i-a83t-emac",
-+ .data = &emac_variant_a83t },
-+ { .compatible = "allwinner,sun50i-a64-emac",
-+ .data = &emac_variant_a64 },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, sun8i_dwmac_match);
-+
-+static struct platform_driver sun8i_dwmac_driver = {
-+ .probe = sun8i_dwmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "dwmac-sun8i",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = sun8i_dwmac_match,
-+ },
-+};
-+module_platform_driver(sun8i_dwmac_driver);
-+
-+MODULE_AUTHOR("Corentin Labbe <clabbe.montjoie@gmail.com>");
-+MODULE_DESCRIPTION("Allwinner sun8i DWMAC specific glue layer");
-+MODULE_LICENSE("GPL");
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-index b82ab64..39777a7 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -235,6 +235,17 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
- else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
- priv->clk_csr = STMMAC_CSR_250_300M;
- }
-+
-+ if (priv->plat->has_sun8i) {
-+ if (clk_rate > 160000000)
-+ priv->clk_csr = 0x03;
-+ else if (clk_rate > 80000000)
-+ priv->clk_csr = 0x02;
-+ else if (clk_rate > 40000000)
-+ priv->clk_csr = 0x01;
-+ else
-+ priv->clk_csr = 0;
-+ }
- }
-
- static void print_pkt(unsigned char *buf, int len)
-@@ -784,6 +795,14 @@ static void stmmac_adjust_link(struct net_device *dev)
- if (phydev->link) {
- u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
-
-+ /* dwmac-sun8i handle loopback in MAC_CTRL_REG */
-+ if (priv->plat->has_sun8i) {
-+ if (dev->features & NETIF_F_LOOPBACK)
-+ ctrl |= BIT(1);
-+ else
-+ ctrl &= ~BIT(1);
-+ }
-+
- /* Now we make sure that we can be in full duplex mode.
- * If not, we operate in half-duplex mode. */
- if (phydev->duplex != priv->oldduplex) {
-@@ -800,6 +819,8 @@ static void stmmac_adjust_link(struct net_device *dev)
-
- if (phydev->speed != priv->speed) {
- new_state = 1;
-+ if (priv->plat->has_sun8i)
-+ ctrl &= ~GENMASK(3, 2);
- switch (phydev->speed) {
- case 1000:
- if (priv->plat->has_gmac ||
-@@ -811,6 +832,8 @@ static void stmmac_adjust_link(struct net_device *dev)
- priv->plat->has_gmac4) {
- ctrl |= priv->hw->link.port;
- ctrl |= priv->hw->link.speed;
-+ } else if (priv->plat->has_sun8i) {
-+ ctrl |= 3 << 2;
- } else {
- ctrl &= ~priv->hw->link.port;
- }
-@@ -820,6 +843,8 @@ static void stmmac_adjust_link(struct net_device *dev)
- priv->plat->has_gmac4) {
- ctrl |= priv->hw->link.port;
- ctrl &= ~(priv->hw->link.speed);
-+ } else if (priv->plat->has_sun8i) {
-+ ctrl |= 2 << 2;
- } else {
- ctrl &= ~priv->hw->link.port;
- }
-@@ -3969,6 +3994,10 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
-
- priv->hw = mac;
-
-+ /* dwmac-sun8i only work in chain mode */
-+ if (priv->plat->has_sun8i)
-+ chain_mode = 1;
-+
- /* To use the chained or ring mode */
- if (priv->synopsys_id >= DWMAC_CORE_4_00) {
- priv->hw->mode = &dwmac4_ring_mode_ops;
-diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-index 7fc3a1e..3840529 100644
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -309,6 +309,12 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
- struct device_node *np, struct device *dev)
- {
- bool mdio = true;
-+ static const struct of_device_id need_mdio_ids[] = {
-+ { .compatible = "snps,dwc-qos-ethernet-4.10" },
-+ { .compatible = "allwinner,sun8i-a83t-emac" },
-+ { .compatible = "allwinner,sun8i-h3-emac" },
-+ { .compatible = "allwinner,sun50i-a64-emac" },
-+ };
-
- /* If phy-handle property is passed from DT, use it as the PHY */
- plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
-@@ -325,8 +331,7 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
- mdio = false;
- }
-
-- /* exception for dwmac-dwc-qos-eth glue logic */
-- if (of_device_is_compatible(np, "snps,dwc-qos-ethernet-4.10")) {
-+ if (of_match_node(need_mdio_ids, np)) {
- plat->mdio_node = of_get_child_by_name(np, "mdio");
- } else {
- /**
-diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h
-index 8bb550b..108739f 100644
---- a/include/linux/stmmac.h
-+++ b/include/linux/stmmac.h
-@@ -186,6 +186,7 @@ struct plat_stmmacenet_data {
- struct reset_control *stmmac_rst;
- struct stmmac_axi *axi;
- int has_gmac4;
-+ bool has_sun8i;
- bool tso_en;
- int mac_port_sel_speed;
- bool en_tx_lpi_clockgating;
-
From patchwork Mon May 1 12:45:18 2017
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0