]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
net: designware: add Amlogic Meson8b & later glue driver
authorNeil Armstrong <narmstrong@baylibre.com>
Wed, 24 Feb 2021 19:33:56 +0000 (20:33 +0100)
committerNeil Armstrong <narmstrong@baylibre.com>
Tue, 6 Apr 2021 09:10:29 +0000 (11:10 +0200)
This adds a proper glue driver for the Designware DWMAC ethernet MAC IP
found in the Amlogic Meson8, GXBB, GXL, GXM, G12A, G12B & SM1 SoCs.

This is aimed to replace the static ethernet link setup found on the board
init code for the Amlogic SoC based boards.

Tested on a libretech-cc (S905x Internal RMII 10/100 PHY) and Khadas VIM3 (A113d
with external 10/100/1000 RGMII PHY) to cover the most extreme setups.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/dwmac_meson8b.c [new file with mode: 0644]

index e1d3b266873cfa110ed81fa0c91f43b8e620ec32..cf062fad4da34484326cba927f9764437fc36eb2 100644 (file)
@@ -271,6 +271,14 @@ config ETH_DESIGNWARE
          100Mbit and 1 Gbit operation. You must enable CONFIG_PHYLIB to
          provide the PHY (physical media interface).
 
+config ETH_DESIGNWARE_MESON8B
+       bool "Amlogic Meson8b and later glue driver for Synopsys Designware Ethernet MAC"
+       depends on DM_ETH
+       select ETH_DESIGNWARE
+       help
+         This provides glue layer to use Synopsys Designware Ethernet MAC
+         present on the Amlogic Meson8b, GX, AXG & G12A SoCs.
+
 config ETH_DESIGNWARE_SOCFPGA
        select REGMAP
        select SYSCON
index 070ae7662c7ac9c7ef42250a1f7119e0a2179c4a..ce7b9e3478b1d72e4a47af34ea20ddd2cff69f27 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_CORTINA_NI_ENET) += cortina_ni.o
 obj-$(CONFIG_CS8900) += cs8900.o
 obj-$(CONFIG_TULIP) += dc2114x.o
 obj-$(CONFIG_ETH_DESIGNWARE) += designware.o
+obj-$(CONFIG_ETH_DESIGNWARE_MESON8B) += dwmac_meson8b.o
 obj-$(CONFIG_ETH_DESIGNWARE_SOCFPGA) += dwmac_socfpga.o
 obj-$(CONFIG_ETH_DESIGNWARE_S700) += dwmac_s700.o
 obj-$(CONFIG_DRIVER_DM9000) += dm9000x.o
diff --git a/drivers/net/dwmac_meson8b.c b/drivers/net/dwmac_meson8b.c
new file mode 100644 (file)
index 0000000..c0b6ef4
--- /dev/null
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2021 BayLibre, SAS
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <phy.h>
+#include "designware.h"
+#include <dm/device_compat.h>
+#include <linux/err.h>
+
+#define ETH_REG_0              0x0
+#define ETH_REG_1              0x4
+#define ETH_REG_2              0x18
+#define ETH_REG_3              0x1c
+
+#define GX_ETH_REG_0_PHY_INTF          BIT(0)
+#define GX_ETH_REG_0_TX_PHASE(x)       (((x) & 3) << 5)
+#define GX_ETH_REG_0_TX_RATIO(x)       (((x) & 7) << 7)
+#define GX_ETH_REG_0_PHY_CLK_EN        BIT(10)
+#define GX_ETH_REG_0_INVERT_RMII_CLK   BIT(11)
+#define GX_ETH_REG_0_CLK_EN            BIT(12)
+
+#define AXG_ETH_REG_0_PHY_INTF_RGMII   BIT(0)
+#define AXG_ETH_REG_0_PHY_INTF_RMII    BIT(2)
+#define AXG_ETH_REG_0_TX_PHASE(x)      (((x) & 3) << 5)
+#define AXG_ETH_REG_0_TX_RATIO(x)      (((x) & 7) << 7)
+#define AXG_ETH_REG_0_PHY_CLK_EN       BIT(10)
+#define AXG_ETH_REG_0_INVERT_RMII_CLK  BIT(11)
+#define AXG_ETH_REG_0_CLK_EN           BIT(12)
+
+struct dwmac_meson8b_plat {
+       struct dw_eth_pdata dw_eth_pdata;
+       int (*dwmac_setup)(struct udevice *dev, struct eth_pdata *edata);
+       void *regs;
+};
+
+static int dwmac_meson8b_of_to_plat(struct udevice *dev)
+{
+       struct dwmac_meson8b_plat *pdata = dev_get_plat(dev);
+
+       pdata->regs = (void *)dev_read_addr_index(dev, 1);
+       if ((fdt_addr_t)pdata->regs == FDT_ADDR_T_NONE)
+               return -EINVAL;
+
+       pdata->dwmac_setup = (void *)dev_get_driver_data(dev);
+       if (!pdata->dwmac_setup)
+               return -EINVAL;
+
+       return designware_eth_of_to_plat(dev);
+}
+
+static int dwmac_setup_axg(struct udevice *dev, struct eth_pdata *edata)
+{
+       struct dwmac_meson8b_plat *plat = dev_get_plat(dev);
+
+       switch (edata->phy_interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               /* Set RGMII mode */
+               setbits_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RGMII |
+                                                    AXG_ETH_REG_0_TX_PHASE(1) |
+                                                    AXG_ETH_REG_0_TX_RATIO(4) |
+                                                    AXG_ETH_REG_0_PHY_CLK_EN |
+                                                    AXG_ETH_REG_0_CLK_EN);
+               break;
+
+       case PHY_INTERFACE_MODE_RMII:
+               /* Set RMII mode */
+               out_le32(plat->regs + ETH_REG_0, AXG_ETH_REG_0_PHY_INTF_RMII |
+                                                AXG_ETH_REG_0_INVERT_RMII_CLK |
+                                                AXG_ETH_REG_0_CLK_EN);
+               break;
+       default:
+               dev_err(dev, "Unsupported PHY mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int dwmac_setup_gx(struct udevice *dev, struct eth_pdata *edata)
+{
+       struct dwmac_meson8b_plat *plat = dev_get_plat(dev);
+
+       switch (edata->phy_interface) {
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               /* Set RGMII mode */
+               setbits_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_PHY_INTF |
+                                                    GX_ETH_REG_0_TX_PHASE(1) |
+                                                    GX_ETH_REG_0_TX_RATIO(4) |
+                                                    GX_ETH_REG_0_PHY_CLK_EN |
+                                                    GX_ETH_REG_0_CLK_EN);
+
+               break;
+
+       case PHY_INTERFACE_MODE_RMII:
+               /* Set RMII mode */
+               out_le32(plat->regs + ETH_REG_0, GX_ETH_REG_0_INVERT_RMII_CLK |
+                                                GX_ETH_REG_0_CLK_EN);
+
+               if (!IS_ENABLED(CONFIG_MESON_GXBB))
+                       writel(0x10110181, plat->regs + ETH_REG_2);
+
+               break;
+       default:
+               dev_err(dev, "Unsupported PHY mode\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int dwmac_meson8b_probe(struct udevice *dev)
+{
+       struct dwmac_meson8b_plat *pdata = dev_get_plat(dev);
+       struct eth_pdata *edata = &pdata->dw_eth_pdata.eth_pdata;
+       int ret;
+
+       ret = pdata->dwmac_setup(dev, edata);
+       if (ret)
+               return ret;
+
+       return designware_eth_probe(dev);
+}
+
+static const struct udevice_id dwmac_meson8b_ids[] = {
+       { .compatible = "amlogic,meson-gxbb-dwmac", .data = (ulong)dwmac_setup_gx },
+       { .compatible = "amlogic,meson-axg-dwmac", .data = (ulong)dwmac_setup_axg },
+       { }
+};
+
+U_BOOT_DRIVER(dwmac_meson8b) = {
+       .name           = "dwmac_meson8b",
+       .id             = UCLASS_ETH,
+       .of_match       = dwmac_meson8b_ids,
+       .of_to_plat = dwmac_meson8b_of_to_plat,
+       .probe          = dwmac_meson8b_probe,
+       .ops            = &designware_eth_ops,
+       .priv_auto      = sizeof(struct dw_eth_dev),
+       .plat_auto      = sizeof(struct dwmac_meson8b_plat),
+       .flags          = DM_FLAG_ALLOC_PRIV_DMA,
+};