]> git.ipfire.org Git - people/arne_f/kernel.git/commitdiff
sunxi: network dwmac sun8i backport from 4.15-rc
authorImport from armbian <no@mail>
Thu, 1 Mar 2018 10:14:14 +0000 (11:14 +0100)
committerArne Fitzenreiter <arne_f@ipfire.org>
Fri, 14 May 2021 13:17:17 +0000 (15:17 +0200)
14 files changed:
arch/arm/boot/dts/sun8i-h3-orangepi-plus2e.dts
arch/arm/boot/dts/sunxi-h3-h5.dtsi
arch/arm64/boot/dts/allwinner/sun50i-h5-nanopi-neo-plus2.dts
arch/arm64/boot/dts/allwinner/sun50i-h5-orangepi-zero-plus.dts
drivers/net/ethernet/stmicro/stmmac/Kconfig
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c
drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c
drivers/net/ethernet/stmicro/stmmac/dwmac4.h
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c

index 80026f3caafc8928043baf01c3d0387301562292..6dbf7b2e0c13c44f06e7970c006f3357f0d0493e 100644 (file)
@@ -71,7 +71,7 @@
        status = "okay";
 };
 
-&mdio {
+&external_mdio {
        ext_rgmii_phy: ethernet-phy@1 {
                compatible = "ethernet-phy-ieee802.3-c22";
                reg = <1>;
index 1d4744ee3ffe98bac135bf1ba267b93e335fe596..0f0a56ec0a54f1e7738b50b6f613f2b0a37bf9a8 100644 (file)
                        mdio: mdio {
                                #address-cells = <1>;
                                #size-cells = <0>;
-                               int_mii_phy: ethernet-phy@1 {
-                                       compatible = "ethernet-phy-ieee802.3-c22";
+                               compatible = "snps,dwmac-mdio";
+                       };
+
+                       mdio-mux {
+                               compatible = "allwinner,sun8i-h3-mdio-mux";
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               mdio-parent-bus = <&mdio>;
+                               /* Only one MDIO is usable at the time */
+                               internal_mdio: mdio@1 {
+                                       compatible = "allwinner,sun8i-h3-mdio-internal";
                                        reg = <1>;
-                                       clocks = <&ccu CLK_BUS_EPHY>;
-                                       resets = <&ccu RST_BUS_EPHY>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
+
+                                       int_mii_phy: ethernet-phy@1 {
+                                               compatible = "ethernet-phy-ieee802.3-c22";
+                                               reg = <1>;
+                                               clocks = <&ccu CLK_BUS_EPHY>;
+                                               resets = <&ccu RST_BUS_EPHY>;
+                                       };
+                               };
+
+                               external_mdio: mdio@2 {
+                                       reg = <2>;
+                                       #address-cells = <1>;
+                                       #size-cells = <0>;
                                };
                        };
                };
index f4be9155067c978eebb008592ccc950c11cfd1e0..d5156e1228b0d3bbdf6dcb8a713b340019bd05d4 100644 (file)
 
                status {
                        label = "nanopi:blue:status";
-                       gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
+                       gpios = <&pio 0 20 GPIO_ACTIVE_HIGH>;
+                       linux,default-trigger = "heartbeat";
                };
        };
 
        reg_gmac_3v3: gmac-3v3 {
                compatible = "regulator-fixed";
+               pinctrl-names = "default";
                regulator-name = "gmac-3v3";
                regulator-min-microvolt = <3300000>;
                regulator-max-microvolt = <3300000>;
        status = "okay";
 };
 
-&mdio {
+&external_mdio {
        ext_rgmii_phy: ethernet-phy@7 {
                compatible = "ethernet-phy-ieee802.3-c22";
                reg = <7>;
index ea9e187b2f59e268f3e0f23e375aa2a1f9ea223c..c3333f61e9005382ff85ed1e5290434b0e2ccb83 100644 (file)
        status = "okay";
 };
 
-&mdio {
+&external_mdio {
        ext_rgmii_phy: ethernet-phy@1 {
                compatible = "ethernet-phy-ieee802.3-c22";
                reg = <1>;
index 5790cd61436d0b2ca73eeb1d1eeab1b759083784..bf4acebb6bcddd8807041a75c000251bbc28f19d 100644 (file)
@@ -159,6 +159,7 @@ config DWMAC_SUN8I
        tristate "Allwinner sun8i GMAC support"
        default ARCH_SUNXI
        depends on OF && (ARCH_SUNXI || COMPILE_TEST)
+       select MDIO_BUS_MUX
        ---help---
          Support for Allwinner H3 A83T A64 EMAC ethernet controllers.
 
index e51b50d94074e7f0976b52481abc78335769bdc9..729195cab41ae115ad6f586cd3d959563ca0edf3 100644 (file)
@@ -442,9 +442,9 @@ struct stmmac_dma_ops {
        void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
                         int rxfifosz);
        void (*dma_rx_mode)(void __iomem *ioaddr, int mode, u32 channel,
-                           int fifosz);
+                           int fifosz, u8 qmode);
        void (*dma_tx_mode)(void __iomem *ioaddr, int mode, u32 channel,
-                           int fifosz);
+                           int fifosz, u8 qmode);
        /* To track extra statistic (if supported) */
        void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
                                   void __iomem *ioaddr);
index 1924788d28da0f4e567b581f4be02173c995067d..826626e870d5cdbb10c42cf28b1ea5f4001772ef 100644 (file)
 #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
@@ -68,9 +64,6 @@
 #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)
 
 #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;
@@ -217,7 +205,7 @@ static int ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
         * 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) {
+       if (gmac->id > 3) {
                dev_err(dev, "invalid gmac id\n");
                return -EINVAL;
        }
index 61cb24810d101194c5285cf27edd963aa488473f..9e6db16af663b5a43c3c1eff26824fab3cb2df6c 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * dwmac-stm32.c - DWMAC Specific Glue layer for STM32 MCU
  *
- * Copyright (C) Alexandre Torgue 2015
- * Author:  Alexandre Torgue <alexandre.torgue@gmail.com>
+ * Copyright (C) STMicroelectronics SA 2017
+ * Author:  Alexandre Torgue <alexandre.torgue@st.com> for STMicroelectronics.
  * License terms:  GNU General Public License (GPL), version 2
  *
  */
index 877aae49a908820bb9a5ddd4cbf9ab32f271af30..af2f3d8015114eb7fed85b90b10b30b54220017c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
+#include <linux/mdio-mux.h>
 #include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/of_device.h>
  *                             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
+ * @soc_has_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 soc_has_internal_phy;
        bool support_mii;
        bool support_rmii;
        bool support_rgmii;
@@ -61,7 +62,8 @@ struct emac_variant {
  * @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
+ * @internal_phy_powered: Does the internal PHY is enabled
+ * @mux_handle:        Internal pointer used by mdio-mux lib
  */
 struct sunxi_priv_data {
        struct clk *tx_clk;
@@ -70,12 +72,13 @@ struct sunxi_priv_data {
        struct reset_control *rst_ephy;
        const struct emac_variant *variant;
        struct regmap *regmap;
-       bool use_internal_phy;
+       bool internal_phy_powered;
+       void *mux_handle;
 };
 
 static const struct emac_variant emac_variant_h3 = {
        .default_syscon_value = 0x58000,
-       .internal_phy = PHY_INTERFACE_MODE_MII,
+       .soc_has_internal_phy = true,
        .support_mii = true,
        .support_rmii = true,
        .support_rgmii = true
@@ -83,20 +86,20 @@ static const struct emac_variant emac_variant_h3 = {
 
 static const struct emac_variant emac_variant_v3s = {
        .default_syscon_value = 0x38000,
-       .internal_phy = PHY_INTERFACE_MODE_MII,
+       .soc_has_internal_phy = true,
        .support_mii = true
 };
 
 static const struct emac_variant emac_variant_a83t = {
        .default_syscon_value = 0,
-       .internal_phy = 0,
+       .soc_has_internal_phy = false,
        .support_mii = true,
        .support_rgmii = true
 };
 
 static const struct emac_variant emac_variant_a64 = {
        .default_syscon_value = 0,
-       .internal_phy = 0,
+       .soc_has_internal_phy = false,
        .support_mii = true,
        .support_rmii = true,
        .support_rgmii = true
@@ -195,6 +198,9 @@ static const struct emac_variant emac_variant_a64 = {
 #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 */
+#define H3_EPHY_MUX_MASK       (H3_EPHY_SHUTDOWN | H3_EPHY_SELECT)
+#define DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID       1
+#define DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID       2
 
 /* H3/A64 specific bits */
 #define SYSCON_RMII_EN         BIT(13) /* 1: enable RMII (overrides EPIT) */
@@ -635,6 +641,159 @@ static int sun8i_dwmac_reset(struct stmmac_priv *priv)
        return 0;
 }
 
+/* Search in mdio-mux node for internal PHY node and get its clk/reset */
+static int get_ephy_nodes(struct stmmac_priv *priv)
+{
+       struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+       struct device_node *mdio_mux, *iphynode;
+       struct device_node *mdio_internal;
+       int ret;
+
+       mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
+       if (!mdio_mux) {
+               dev_err(priv->device, "Cannot get mdio-mux node\n");
+               return -ENODEV;
+       }
+
+       mdio_internal = of_find_compatible_node(mdio_mux, NULL,
+                                               "allwinner,sun8i-h3-mdio-internal");
+       if (!mdio_internal) {
+               dev_err(priv->device, "Cannot get internal_mdio node\n");
+               return -ENODEV;
+       }
+
+       /* Seek for internal PHY */
+       for_each_child_of_node(mdio_internal, iphynode) {
+               gmac->ephy_clk = of_clk_get(iphynode, 0);
+               if (IS_ERR(gmac->ephy_clk))
+                       continue;
+               gmac->rst_ephy = of_reset_control_get_exclusive(iphynode, NULL);
+               if (IS_ERR(gmac->rst_ephy)) {
+                       ret = PTR_ERR(gmac->rst_ephy);
+                       if (ret == -EPROBE_DEFER)
+                               return ret;
+                       continue;
+               }
+               dev_info(priv->device, "Found internal PHY node\n");
+               return 0;
+       }
+       return -ENODEV;
+}
+
+static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
+{
+       struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+       int ret;
+
+       if (gmac->internal_phy_powered) {
+               dev_warn(priv->device, "Internal PHY already powered\n");
+               return 0;
+       }
+
+       dev_info(priv->device, "Powering internal PHY\n");
+       ret = clk_prepare_enable(gmac->ephy_clk);
+       if (ret) {
+               dev_err(priv->device, "Cannot enable internal PHY\n");
+               return ret;
+       }
+
+       /* Make sure the EPHY is properly reseted, as U-Boot may leave
+        * it at deasserted state, and thus it may fail to reset EMAC.
+        */
+       reset_control_assert(gmac->rst_ephy);
+
+       ret = reset_control_deassert(gmac->rst_ephy);
+       if (ret) {
+               dev_err(priv->device, "Cannot deassert internal phy\n");
+               clk_disable_unprepare(gmac->ephy_clk);
+               return ret;
+       }
+
+       gmac->internal_phy_powered = true;
+
+       return 0;
+}
+
+static int sun8i_dwmac_unpower_internal_phy(struct sunxi_priv_data *gmac)
+{
+       if (!gmac->internal_phy_powered)
+               return 0;
+
+       clk_disable_unprepare(gmac->ephy_clk);
+       reset_control_assert(gmac->rst_ephy);
+       gmac->internal_phy_powered = false;
+       return 0;
+}
+
+/* MDIO multiplexing switch function
+ * This function is called by the mdio-mux layer when it thinks the mdio bus
+ * multiplexer needs to switch.
+ * 'current_child' is the current value of the mux register
+ * 'desired_child' is the value of the 'reg' property of the target child MDIO
+ * node.
+ * The first time this function is called, current_child == -1.
+ * If current_child == desired_child, then the mux is already set to the
+ * correct bus.
+ */
+static int mdio_mux_syscon_switch_fn(int current_child, int desired_child,
+                                    void *data)
+{
+       struct stmmac_priv *priv = data;
+       struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+       u32 reg, val;
+       int ret = 0;
+       bool need_power_ephy = false;
+
+       if (current_child ^ desired_child) {
+               regmap_read(gmac->regmap, SYSCON_EMAC_REG, &reg);
+               switch (desired_child) {
+               case DWMAC_SUN8I_MDIO_MUX_INTERNAL_ID:
+                       dev_info(priv->device, "Switch mux to internal PHY");
+                       val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SELECT;
+
+                       need_power_ephy = true;
+                       break;
+               case DWMAC_SUN8I_MDIO_MUX_EXTERNAL_ID:
+                       dev_info(priv->device, "Switch mux to external PHY");
+                       val = (reg & ~H3_EPHY_MUX_MASK) | H3_EPHY_SHUTDOWN;
+                       need_power_ephy = false;
+                       break;
+               default:
+                       dev_err(priv->device, "Invalid child ID %x\n",
+                               desired_child);
+                       return -EINVAL;
+               }
+               regmap_write(gmac->regmap, SYSCON_EMAC_REG, val);
+               if (need_power_ephy) {
+                       ret = sun8i_dwmac_power_internal_phy(priv);
+                       if (ret)
+                               return ret;
+               } else {
+                       sun8i_dwmac_unpower_internal_phy(gmac);
+               }
+               /* After changing syscon value, the MAC need reset or it will
+                * use the last value (and so the last PHY set).
+                */
+               ret = sun8i_dwmac_reset(priv);
+       }
+       return ret;
+}
+
+static int sun8i_dwmac_register_mdio_mux(struct stmmac_priv *priv)
+{
+       int ret;
+       struct device_node *mdio_mux;
+       struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
+
+       mdio_mux = of_get_child_by_name(priv->device->of_node, "mdio-mux");
+       if (!mdio_mux)
+               return -ENODEV;
+
+       ret = mdio_mux_init(priv->device, mdio_mux, mdio_mux_syscon_switch_fn,
+                           &gmac->mux_handle, priv, priv->mii);
+       return ret;
+}
+
 static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
 {
        struct sunxi_priv_data *gmac = priv->plat->bsp_priv;
@@ -649,35 +808,24 @@ static int sun8i_dwmac_set_syscon(struct stmmac_priv *priv)
                         "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;
-
-                       /* Force EPHY xtal frequency to 24MHz. */
-                       reg |= H3_EPHY_CLK_SEL;
-
-                       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 (gmac->variant->soc_has_internal_phy) {
+               if (of_property_read_bool(node, "allwinner,leds-active-low"))
+                       reg |= H3_EPHY_LED_POL;
+               else
+                       reg &= ~H3_EPHY_LED_POL;
+
+               /* Force EPHY xtal frequency to 24MHz. */
+               reg |= H3_EPHY_CLK_SEL;
+
+               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 |= 1 << H3_EPHY_ADDR_SHIFT;
        }
 
        if (!of_property_read_u32(node, "allwinner,tx-delay-ps", &val)) {
@@ -750,81 +898,21 @@ static void sun8i_dwmac_unset_syscon(struct sunxi_priv_data *gmac)
        regmap_write(gmac->regmap, SYSCON_EMAC_REG, reg);
 }
 
-static int sun8i_dwmac_power_internal_phy(struct stmmac_priv *priv)
+static void sun8i_dwmac_exit(struct platform_device *pdev, void *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;
-       }
-
-       /* Make sure the EPHY is properly reseted, as U-Boot may leave
-        * it at deasserted state, and thus it may fail to reset EMAC.
-        */
-       reset_control_assert(gmac->rst_ephy);
+       struct sunxi_priv_data *gmac = priv;
 
-       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;
+       if (gmac->variant->soc_has_internal_phy) {
+               /* sun8i_dwmac_exit could be called with mdiomux uninit */
+               if (gmac->mux_handle)
+                       mdio_mux_uninit(gmac->mux_handle);
+               if (gmac->internal_phy_powered)
+                       sun8i_dwmac_unpower_internal_phy(gmac);
        }
 
-       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;
-}
-
-/* sun8i_power_phy() - Activate the PHY:
- * In case of error, no need to call sun8i_unpower_phy(),
- * it will be called anyway by sun8i_dwmac_exit()
- */
-static int sun8i_power_phy(struct stmmac_priv *priv)
-{
-       int ret;
-
-       ret = sun8i_dwmac_power_internal_phy(priv);
-       if (ret)
-               return ret;
-
-       ret = sun8i_dwmac_set_syscon(priv);
-       if (ret)
-               return ret;
-
-       /* After changing syscon value, the MAC need reset or it will use
-        * the last value (and so the last PHY set.
-        */
-       ret = sun8i_dwmac_reset(priv);
-       if (ret)
-               return ret;
-       return 0;
-}
-
-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);
+       reset_control_put(gmac->rst_ephy);
 
        clk_disable_unprepare(gmac->tx_clk);
 
@@ -853,7 +941,7 @@ static struct mac_device_info *sun8i_dwmac_setup(void *ppriv)
        if (!mac)
                return NULL;
 
-       ret = sun8i_power_phy(priv);
+       ret = sun8i_dwmac_set_syscon(priv);
        if (ret)
                return NULL;
 
@@ -895,6 +983,8 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
        struct sunxi_priv_data *gmac;
        struct device *dev = &pdev->dev;
        int ret;
+       struct stmmac_priv *priv;
+       struct net_device *ndev;
 
        ret = stmmac_get_platform_resources(pdev, &stmmac_res);
        if (ret)
@@ -938,29 +1028,6 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
        }
 
        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.
@@ -981,9 +1048,34 @@ static int sun8i_dwmac_probe(struct platform_device *pdev)
 
        ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
        if (ret)
-               sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
+               goto dwmac_exit;
+
+       ndev = dev_get_drvdata(&pdev->dev);
+       priv = netdev_priv(ndev);
+       /* The mux must be registered after parent MDIO
+        * so after stmmac_dvr_probe()
+        */
+       if (gmac->variant->soc_has_internal_phy) {
+               ret = get_ephy_nodes(priv);
+               if (ret)
+                       goto dwmac_exit;
+               ret = sun8i_dwmac_register_mdio_mux(priv);
+               if (ret) {
+                       dev_err(&pdev->dev, "Failed to register mux\n");
+                       goto dwmac_mux;
+               }
+       } else {
+               ret = sun8i_dwmac_reset(priv);
+               if (ret)
+                       goto dwmac_exit;
+       }
 
        return ret;
+dwmac_mux:
+       sun8i_dwmac_unset_syscon(gmac);
+dwmac_exit:
+       sun8i_dwmac_exit(pdev, plat_dat->bsp_priv);
+return ret;
 }
 
 static const struct of_device_id sun8i_dwmac_match[] = {
index db5f2aee360b177215fe1251407f39d00ac2e30e..31af98ba760e9158be5c0a6fae0e520034321f61 100644 (file)
@@ -98,7 +98,7 @@
 #define        GMAC_PCS_IRQ_DEFAULT    (GMAC_INT_RGSMIIS | GMAC_INT_PCS_LINK | \
                                 GMAC_INT_PCS_ANE)
 
-#define        GMAC_INT_DEFAULT_MASK   GMAC_INT_PMT_EN
+#define        GMAC_INT_DEFAULT_MASK   (GMAC_INT_PMT_EN | GMAC_INT_LPI_EN)
 
 enum dwmac4_irq_status {
        time_stamp_irq = 0x00001000,
@@ -106,6 +106,7 @@ enum dwmac4_irq_status {
        mmc_tx_irq = 0x00000400,
        mmc_rx_irq = 0x00000200,
        mmc_irq = 0x00000100,
+       lpi_irq = 0x00000020,
        pmt_irq = 0x00000010,
 };
 
@@ -132,6 +133,10 @@ enum power_event {
 #define GMAC4_LPI_CTRL_STATUS_LPITXA   BIT(19) /* Enable LPI TX Automate */
 #define GMAC4_LPI_CTRL_STATUS_PLS      BIT(17) /* PHY Link Status */
 #define GMAC4_LPI_CTRL_STATUS_LPIEN    BIT(16) /* LPI Enable */
+#define GMAC4_LPI_CTRL_STATUS_RLPIEX   BIT(3) /* Receive LPI Exit */
+#define GMAC4_LPI_CTRL_STATUS_RLPIEN   BIT(2) /* Receive LPI Entry */
+#define GMAC4_LPI_CTRL_STATUS_TLPIEX   BIT(1) /* Transmit LPI Exit */
+#define GMAC4_LPI_CTRL_STATUS_TLPIEN   BIT(0) /* Transmit LPI Entry */
 
 /* MAC Debug bitmap */
 #define GMAC_DEBUG_TFCSTS_MASK         GENMASK(18, 17)
@@ -225,6 +230,8 @@ enum power_event {
 #define MTL_CHAN_RX_DEBUG(x)           (MTL_CHANX_BASE_ADDR(x) + 0x38)
 
 #define MTL_OP_MODE_RSF                        BIT(5)
+#define MTL_OP_MODE_TXQEN_MASK         GENMASK(3, 2)
+#define MTL_OP_MODE_TXQEN_AV           BIT(2)
 #define MTL_OP_MODE_TXQEN              BIT(3)
 #define MTL_OP_MODE_TSF                        BIT(1)
 
index e5566c121525d1739dec7b46c7102b703be31a8e..52a663e0a8784289fbeaf17f142e61f4a8983e66 100644 (file)
@@ -595,6 +595,25 @@ static int dwmac4_irq_status(struct mac_device_info *hw,
                x->irq_receive_pmt_irq_n++;
        }
 
+       /* MAC tx/rx EEE LPI entry/exit interrupts */
+       if (intr_status & lpi_irq) {
+               /* Clear LPI interrupt by reading MAC_LPI_Control_Status */
+               u32 status = readl(ioaddr + GMAC4_LPI_CTRL_STATUS);
+
+               if (status & GMAC4_LPI_CTRL_STATUS_TLPIEN) {
+                       ret |= CORE_IRQ_TX_PATH_IN_LPI_MODE;
+                       x->irq_tx_path_in_lpi_mode_n++;
+               }
+               if (status & GMAC4_LPI_CTRL_STATUS_TLPIEX) {
+                       ret |= CORE_IRQ_TX_PATH_EXIT_LPI_MODE;
+                       x->irq_tx_path_exit_lpi_mode_n++;
+               }
+               if (status & GMAC4_LPI_CTRL_STATUS_RLPIEN)
+                       x->irq_rx_path_in_lpi_mode_n++;
+               if (status & GMAC4_LPI_CTRL_STATUS_RLPIEX)
+                       x->irq_rx_path_exit_lpi_mode_n++;
+       }
+
        dwmac_pcs_isr(ioaddr, GMAC_PCS_BASE, intr_status, x);
        if (intr_status & PCS_RGSMIIIS_IRQ)
                dwmac4_phystatus(ioaddr, x);
index fdca4d1cedbac4e20604a22d0c4bdaf23e186d92..54a58d86796924f1af5034f82f40bc836745ade7 100644 (file)
@@ -208,7 +208,7 @@ static void dwmac4_rx_watchdog(void __iomem *ioaddr, u32 riwt, u32 number_chan)
 }
 
 static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
-                                      u32 channel, int fifosz)
+                                      u32 channel, int fifosz, u8 qmode)
 {
        unsigned int rqs = fifosz / 256 - 1;
        u32 mtl_rx_op, mtl_rx_int;
@@ -235,8 +235,10 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
        mtl_rx_op &= ~MTL_OP_MODE_RQS_MASK;
        mtl_rx_op |= rqs << MTL_OP_MODE_RQS_SHIFT;
 
-       /* enable flow control only if each channel gets 4 KiB or more FIFO */
-       if (fifosz >= 4096) {
+       /* Enable flow control only if each channel gets 4 KiB or more FIFO and
+        * only if channel is not an AVB channel.
+        */
+       if ((fifosz >= 4096) && (qmode != MTL_QUEUE_AVB)) {
                unsigned int rfd, rfa;
 
                mtl_rx_op |= MTL_OP_MODE_EHFC;
@@ -288,7 +290,7 @@ static void dwmac4_dma_rx_chan_op_mode(void __iomem *ioaddr, int mode,
 }
 
 static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
-                                      u32 channel, int fifosz)
+                                      u32 channel, int fifosz, u8 qmode)
 {
        u32 mtl_tx_op = readl(ioaddr + MTL_CHAN_TX_OP_MODE(channel));
        unsigned int tqs = fifosz / 256 - 1;
@@ -328,7 +330,11 @@ static void dwmac4_dma_tx_chan_op_mode(void __iomem *ioaddr, int mode,
         * reflect the available fifo size per queue (total fifo size / number
         * of enabled queues).
         */
-       mtl_tx_op |= MTL_OP_MODE_TXQEN;
+       mtl_tx_op &= ~MTL_OP_MODE_TXQEN_MASK;
+       if (qmode != MTL_QUEUE_AVB)
+               mtl_tx_op |= MTL_OP_MODE_TXQEN;
+       else
+               mtl_tx_op |= MTL_OP_MODE_TXQEN_AV;
        mtl_tx_op &= ~MTL_OP_MODE_TQS_MASK;
        mtl_tx_op |= tqs << MTL_OP_MODE_TQS_SHIFT;
 
index a7b30f0605362e1b73e6a9eeb0d06263372c64b0..a90a1ff5b29d3a3c4813cab4c4cdb161ec7a9ce8 100644 (file)
@@ -1784,6 +1784,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
        u32 txmode = 0;
        u32 rxmode = 0;
        u32 chan = 0;
+       u8 qmode = 0;
 
        if (rxfifosz == 0)
                rxfifosz = priv->dma_cap.rx_fifo_size;
@@ -1815,13 +1816,19 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 
        /* configure all channels */
        if (priv->synopsys_id >= DWMAC_CORE_4_00) {
-               for (chan = 0; chan < rx_channels_count; chan++)
+               for (chan = 0; chan < rx_channels_count; chan++) {
+                       qmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+
                        priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
-                                                  rxfifosz);
+                                                  rxfifosz, qmode);
+               }
+
+               for (chan = 0; chan < tx_channels_count; chan++) {
+                       qmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
 
-               for (chan = 0; chan < tx_channels_count; chan++)
                        priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
-                                                  txfifosz);
+                                                  txfifosz, qmode);
+               }
        } else {
                priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
                                        rxfifosz);
@@ -1990,6 +1997,8 @@ static void stmmac_tx_err(struct stmmac_priv *priv, u32 chan)
 static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
                                          u32 rxmode, u32 chan)
 {
+       u8 rxqmode = priv->plat->rx_queues_cfg[chan].mode_to_use;
+       u8 txqmode = priv->plat->tx_queues_cfg[chan].mode_to_use;
        u32 rx_channels_count = priv->plat->rx_queues_to_use;
        u32 tx_channels_count = priv->plat->tx_queues_to_use;
        int rxfifosz = priv->plat->rx_fifo_size;
@@ -2006,9 +2015,9 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
 
        if (priv->synopsys_id >= DWMAC_CORE_4_00) {
                priv->hw->dma->dma_rx_mode(priv->ioaddr, rxmode, chan,
-                                          rxfifosz);
+                                          rxfifosz, rxqmode);
                priv->hw->dma->dma_tx_mode(priv->ioaddr, txmode, chan,
-                                          txfifosz);
+                                          txfifosz, txqmode);
        } else {
                priv->hw->dma->dma_mode(priv->ioaddr, txmode, rxmode,
                                        rxfifosz);
index d48cc32dc50735246697d32756544be97d465480..94b366b1f1394f4155cc96924d3d8369d41de391 100644 (file)
@@ -317,10 +317,6 @@ static int stmmac_dt_phy(struct plat_stmmacenet_data *plat,
        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,sun8i-v3s-emac" },
-               { .compatible = "allwinner,sun50i-a64-emac" },
                {},
        };