This patch series will provide better support for Mediatek ethernet and add support for Airoha AN8855. Signed-off-by: Shiji Yang <yangshiji66@qq.com>
6312 lines
174 KiB
Diff
6312 lines
174 KiB
Diff
From 626cdca5b68acdc72d2533e2ed2306c06f296725 Mon Sep 17 00:00:00 2001
|
|
From: Weijie Gao <weijie.gao@mediatek.com>
|
|
Date: Fri, 10 Jan 2025 16:41:13 +0800
|
|
Subject: [PATCH 1/3] net: mediatek: split ethernet switch code from mtk_eth.c
|
|
|
|
mtk_eth.c contains not only the ethernet GMAC/DMA driver, but also
|
|
some ethernet switch initialization code. As we may add more switch
|
|
support in the future, it's better to move them out of mtk_eth.c to
|
|
avoid increasing the code complexity.
|
|
|
|
Since not all switches are supported for a particular board, Kconfig
|
|
options are added to allow user to select which switch should be
|
|
built into u-boot. If multiple switches are selected, auto-detecting
|
|
can also be enabled.
|
|
|
|
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
|
|
---
|
|
drivers/net/Kconfig | 21 +-
|
|
drivers/net/Makefile | 2 +-
|
|
drivers/net/mtk_eth/Kconfig | 35 +
|
|
drivers/net/mtk_eth/Makefile | 9 +
|
|
drivers/net/mtk_eth/mt7530.c | 281 ++++++++
|
|
drivers/net/mtk_eth/mt7531.c | 293 +++++++++
|
|
drivers/net/mtk_eth/mt753x.c | 262 ++++++++
|
|
drivers/net/mtk_eth/mt753x.h | 286 ++++++++
|
|
drivers/net/mtk_eth/mt7988.c | 160 +++++
|
|
drivers/net/{ => mtk_eth}/mtk_eth.c | 971 ++++------------------------
|
|
drivers/net/{ => mtk_eth}/mtk_eth.h | 301 ++-------
|
|
11 files changed, 1520 insertions(+), 1101 deletions(-)
|
|
create mode 100644 drivers/net/mtk_eth/Kconfig
|
|
create mode 100644 drivers/net/mtk_eth/Makefile
|
|
create mode 100644 drivers/net/mtk_eth/mt7530.c
|
|
create mode 100644 drivers/net/mtk_eth/mt7531.c
|
|
create mode 100644 drivers/net/mtk_eth/mt753x.c
|
|
create mode 100644 drivers/net/mtk_eth/mt753x.h
|
|
create mode 100644 drivers/net/mtk_eth/mt7988.c
|
|
rename drivers/net/{ => mtk_eth}/mtk_eth.c (62%)
|
|
rename drivers/net/{ => mtk_eth}/mtk_eth.h (59%)
|
|
|
|
--- a/drivers/net/Kconfig
|
|
+++ b/drivers/net/Kconfig
|
|
@@ -966,26 +966,7 @@ config TSEC_ENET
|
|
This driver implements support for the (Enhanced) Three-Speed
|
|
Ethernet Controller found on Freescale SoCs.
|
|
|
|
-config MEDIATEK_ETH
|
|
- bool "MediaTek Ethernet GMAC Driver"
|
|
- select PHYLIB
|
|
- select DM_GPIO
|
|
- select DM_RESET
|
|
- help
|
|
- This Driver support MediaTek Ethernet GMAC
|
|
- Say Y to enable support for the MediaTek Ethernet GMAC.
|
|
-
|
|
-if MEDIATEK_ETH
|
|
-
|
|
-config MTK_ETH_SGMII
|
|
- bool
|
|
- default y if ARCH_MEDIATEK && !TARGET_MT7623
|
|
-
|
|
-config MTK_ETH_XGMII
|
|
- bool
|
|
- default y if TARGET_MT7987 || TARGET_MT7988
|
|
-
|
|
-endif # MEDIATEK_ETH
|
|
+source "drivers/net/mtk_eth/Kconfig"
|
|
|
|
config HIFEMAC_ETH
|
|
bool "HiSilicon Fast Ethernet Controller"
|
|
--- a/drivers/net/Makefile
|
|
+++ b/drivers/net/Makefile
|
|
@@ -67,7 +67,7 @@ obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio
|
|
obj-$(CONFIG_MDIO_MUX_MMIOREG) += mdio_mux_mmioreg.o
|
|
obj-$(CONFIG_MDIO_MUX_SANDBOX) += mdio_mux_sandbox.o
|
|
obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o
|
|
-obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o
|
|
+obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth/
|
|
obj-$(CONFIG_MPC8XX_FEC) += mpc8xx_fec.o
|
|
obj-$(CONFIG_MT7620_ETH) += mt7620-eth.o
|
|
obj-$(CONFIG_MT7628_ETH) += mt7628-eth.o
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/Kconfig
|
|
@@ -0,0 +1,35 @@
|
|
+
|
|
+config MEDIATEK_ETH
|
|
+ bool "MediaTek Ethernet GMAC Driver"
|
|
+ select PHYLIB
|
|
+ select DM_GPIO
|
|
+ select DM_RESET
|
|
+ help
|
|
+ This Driver support MediaTek Ethernet GMAC
|
|
+ Say Y to enable support for the MediaTek Ethernet GMAC.
|
|
+
|
|
+if MEDIATEK_ETH
|
|
+
|
|
+config MTK_ETH_SGMII
|
|
+ bool
|
|
+ default y if ARCH_MEDIATEK && !TARGET_MT7623
|
|
+
|
|
+config MTK_ETH_XGMII
|
|
+ bool
|
|
+ default y if TARGET_MT7988
|
|
+
|
|
+config MTK_ETH_SWITCH_MT7530
|
|
+ bool "Support for MediaTek MT7530 ethernet switch"
|
|
+ default y if TARGET_MT7623 || SOC_MT7621
|
|
+
|
|
+config MTK_ETH_SWITCH_MT7531
|
|
+ bool "Support for MediaTek MT7531 ethernet switch"
|
|
+ default y if TARGET_MT7622 || TARGET_MT7629 || TARGET_MT7981 || \
|
|
+ TARGET_MT7986
|
|
+
|
|
+config MTK_ETH_SWITCH_MT7988
|
|
+ bool "Support for MediaTek MT7988 built-in ethernet switch"
|
|
+ depends on TARGET_MT7988
|
|
+ default y
|
|
+
|
|
+endif # MEDIATEK_ETH
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/Makefile
|
|
@@ -0,0 +1,9 @@
|
|
+# SPDX-License-Identifier: GPL-2.0+
|
|
+#
|
|
+# Copyright (C) 2025 MediaTek Inc.
|
|
+# Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+
|
|
+obj-y += mtk_eth.o
|
|
+obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o
|
|
+obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o
|
|
+obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mt7530.c
|
|
@@ -0,0 +1,281 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#include <miiphy.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/mdio.h>
|
|
+#include <linux/mii.h>
|
|
+#include "mtk_eth.h"
|
|
+#include "mt753x.h"
|
|
+
|
|
+#define CHIP_REV 0x7ffc
|
|
+#define CHIP_NAME_S 16
|
|
+#define CHIP_NAME_M 0xffff0000
|
|
+#define CHIP_REV_S 0
|
|
+#define CHIP_REV_M 0x0f
|
|
+
|
|
+static void mt7530_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
|
|
+ u32 val)
|
|
+{
|
|
+ u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
|
|
+
|
|
+ mtk_mmd_ind_write(priv->epriv.eth, phy_addr, 0x1f, reg, val);
|
|
+}
|
|
+
|
|
+static int mt7530_pad_clk_setup(struct mt753x_switch_priv *priv, int mode)
|
|
+{
|
|
+ u32 ncpo1, ssc_delta;
|
|
+
|
|
+ switch (mode) {
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ ncpo1 = 0x0c80;
|
|
+ ssc_delta = 0x87;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ printf("error: xMII mode %d is not supported\n", mode);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Disable MT7530 core clock */
|
|
+ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
|
|
+
|
|
+ /* Disable MT7530 PLL */
|
|
+ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
|
|
+ (2 << RG_GSWPLL_POSDIV_200M_S) |
|
|
+ (32 << RG_GSWPLL_FBKDIV_200M_S));
|
|
+
|
|
+ /* For MT7530 core clock = 500Mhz */
|
|
+ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2,
|
|
+ (1 << RG_GSWPLL_POSDIV_500M_S) |
|
|
+ (25 << RG_GSWPLL_FBKDIV_500M_S));
|
|
+
|
|
+ /* Enable MT7530 PLL */
|
|
+ mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
|
|
+ (2 << RG_GSWPLL_POSDIV_200M_S) |
|
|
+ (32 << RG_GSWPLL_FBKDIV_200M_S) |
|
|
+ RG_GSWPLL_EN_PRE);
|
|
+
|
|
+ udelay(20);
|
|
+
|
|
+ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
|
|
+
|
|
+ /* Setup the MT7530 TRGMII Tx Clock */
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0);
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
|
|
+ RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
|
|
+
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP2,
|
|
+ RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
|
|
+ (1 << RG_SYSPLL_POSDIV_S));
|
|
+
|
|
+ mt7530_core_reg_write(priv, CORE_PLL_GROUP7,
|
|
+ RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
|
|
+ RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
|
|
+
|
|
+ /* Enable MT7530 core clock */
|
|
+ mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
|
|
+ REG_GSWCK_EN | REG_TRGMIICK_EN);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mt7530_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+ u32 pmcr = FORCE_MODE;
|
|
+
|
|
+ if (enable)
|
|
+ pmcr = priv->pmcr;
|
|
+
|
|
+ mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
|
+}
|
|
+
|
|
+static int mt7530_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = bus->priv;
|
|
+
|
|
+ if (devad < 0)
|
|
+ return mtk_mii_read(priv->epriv.eth, addr, reg);
|
|
+
|
|
+ return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
|
|
+}
|
|
+
|
|
+static int mt7530_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
|
+ u16 val)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = bus->priv;
|
|
+
|
|
+ if (devad < 0)
|
|
+ return mtk_mii_write(priv->epriv.eth, addr, reg, val);
|
|
+
|
|
+ return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
|
|
+}
|
|
+
|
|
+static int mt7530_mdio_register(struct mt753x_switch_priv *priv)
|
|
+{
|
|
+ struct mii_dev *mdio_bus = mdio_alloc();
|
|
+ int ret;
|
|
+
|
|
+ if (!mdio_bus)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ mdio_bus->read = mt7530_mdio_read;
|
|
+ mdio_bus->write = mt7530_mdio_write;
|
|
+ snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
|
|
+
|
|
+ mdio_bus->priv = priv;
|
|
+
|
|
+ ret = mdio_register(mdio_bus);
|
|
+ if (ret) {
|
|
+ mdio_free(mdio_bus);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ priv->mdio_bus = mdio_bus;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt7530_setup(struct mtk_eth_switch_priv *swpriv)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+ u16 phy_addr, phy_val;
|
|
+ u32 i, val, txdrv;
|
|
+
|
|
+ priv->smi_addr = MT753X_DFL_SMI_ADDR;
|
|
+ priv->reg_read = mt753x_mdio_reg_read;
|
|
+ priv->reg_write = mt753x_mdio_reg_write;
|
|
+
|
|
+ if (!MTK_HAS_CAPS(priv->epriv.soc->caps, MTK_TRGMII_MT7621_CLK)) {
|
|
+ /* Select 250MHz clk for RGMII mode */
|
|
+ mtk_ethsys_rmw(priv->epriv.eth, ETHSYS_CLKCFG0_REG,
|
|
+ ETHSYS_TRGMII_CLK_SEL362_5, 0);
|
|
+
|
|
+ txdrv = 8;
|
|
+ } else {
|
|
+ txdrv = 4;
|
|
+ }
|
|
+
|
|
+ /* Modify HWTRAP first to allow direct access to internal PHYs */
|
|
+ mt753x_reg_read(priv, HWTRAP_REG, &val);
|
|
+ val |= CHG_TRAP;
|
|
+ val &= ~C_MDIO_BPS;
|
|
+ mt753x_reg_write(priv, MHWTRAP_REG, val);
|
|
+
|
|
+ /* Calculate the phy base address */
|
|
+ val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
|
|
+ priv->phy_base = (val | 0x7) + 1;
|
|
+
|
|
+ /* Turn off PHYs */
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
|
+ phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
|
|
+ phy_val |= BMCR_PDOWN;
|
|
+ mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
|
|
+ }
|
|
+
|
|
+ /* Force MAC link down before reset */
|
|
+ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
|
|
+ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
|
|
+
|
|
+ /* MT7530 reset */
|
|
+ mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
|
|
+ udelay(100);
|
|
+
|
|
+ val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
+ MAC_MODE | FORCE_MODE |
|
|
+ MAC_TX_EN | MAC_RX_EN |
|
|
+ BKOFF_EN | BACKPR_EN |
|
|
+ (SPEED_1000M << FORCE_SPD_S) |
|
|
+ FORCE_DPX | FORCE_LINK;
|
|
+
|
|
+ /* MT7530 Port6: Forced 1000M/FD, FC disabled */
|
|
+ priv->pmcr = val;
|
|
+
|
|
+ /* MT7530 Port5: Forced link down */
|
|
+ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
|
|
+
|
|
+ /* Keep MAC link down before starting eth */
|
|
+ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
|
|
+
|
|
+ /* MT7530 Port6: Set to RGMII */
|
|
+ mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
|
|
+
|
|
+ /* Hardware Trap: Enable Port6, Disable Port5 */
|
|
+ mt753x_reg_read(priv, HWTRAP_REG, &val);
|
|
+ val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
|
|
+ (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
|
|
+ (P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
|
|
+ val &= ~(C_MDIO_BPS | P6_INTF_DIS);
|
|
+ mt753x_reg_write(priv, MHWTRAP_REG, val);
|
|
+
|
|
+ /* Setup switch core pll */
|
|
+ mt7530_pad_clk_setup(priv, priv->epriv.phy_interface);
|
|
+
|
|
+ /* Lower Tx Driving for TRGMII path */
|
|
+ for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
|
|
+ mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
|
|
+ (txdrv << TD_DM_DRVP_S) |
|
|
+ (txdrv << TD_DM_DRVN_S));
|
|
+
|
|
+ for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
|
|
+ mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
|
|
+
|
|
+ /* Enable port isolation to block inter-port communication */
|
|
+ mt753x_port_isolation(priv);
|
|
+
|
|
+ /* Turn on PHYs */
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
|
+ phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
|
|
+ phy_val &= ~BMCR_PDOWN;
|
|
+ mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
|
|
+ }
|
|
+
|
|
+ return mt7530_mdio_register(priv);
|
|
+}
|
|
+
|
|
+static int mt7530_cleanup(struct mtk_eth_switch_priv *swpriv)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+
|
|
+ mdio_unregister(priv->mdio_bus);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt7530_detect(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ int ret;
|
|
+ u32 rev;
|
|
+
|
|
+ ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7530)
|
|
+ return 0;
|
|
+
|
|
+ return -ENODEV;
|
|
+}
|
|
+
|
|
+MTK_ETH_SWITCH(mt7530) = {
|
|
+ .name = "mt7530",
|
|
+ .desc = "MediaTek MT7530",
|
|
+ .priv_size = sizeof(struct mt753x_switch_priv),
|
|
+ .reset_wait_time = 1000,
|
|
+
|
|
+ .detect = mt7530_detect,
|
|
+ .setup = mt7530_setup,
|
|
+ .cleanup = mt7530_cleanup,
|
|
+ .mac_control = mt7530_mac_control,
|
|
+};
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mt7531.c
|
|
@@ -0,0 +1,293 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#include <miiphy.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/mdio.h>
|
|
+#include <linux/mii.h>
|
|
+#include "mtk_eth.h"
|
|
+#include "mt753x.h"
|
|
+
|
|
+#define CHIP_REV 0x781C
|
|
+#define CHIP_NAME_S 16
|
|
+#define CHIP_NAME_M 0xffff0000
|
|
+#define CHIP_REV_S 0
|
|
+#define CHIP_REV_M 0x0f
|
|
+#define CHIP_REV_E1 0x0
|
|
+
|
|
+static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg)
|
|
+{
|
|
+ u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
|
|
+
|
|
+ return mt7531_mmd_read(priv, phy_addr, 0x1f, reg);
|
|
+}
|
|
+
|
|
+static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
|
|
+ u32 val)
|
|
+{
|
|
+ u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
|
|
+
|
|
+ mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val);
|
|
+}
|
|
+
|
|
+static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv)
|
|
+{
|
|
+ /* Step 1 : Disable MT7531 COREPLL */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
|
|
+
|
|
+ /* Step 2: switch to XTAL output */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
|
|
+
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
|
|
+
|
|
+ /* Step 3: disable PLLGP and enable program PLLGP */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
|
|
+
|
|
+ /* Step 4: program COREPLL output frequency to 500MHz */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
|
|
+ 2 << RG_COREPLL_POSDIV_S);
|
|
+ udelay(25);
|
|
+
|
|
+ /* Currently, support XTAL 25Mhz only */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
|
|
+ 0x140000 << RG_COREPLL_SDM_PCW_S);
|
|
+
|
|
+ /* Set feedback divide ratio update signal to high */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
|
|
+ RG_COREPLL_SDM_PCW_CHG);
|
|
+
|
|
+ /* Wait for at least 16 XTAL clocks */
|
|
+ udelay(10);
|
|
+
|
|
+ /* Step 5: set feedback divide ratio update signal to low */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
|
|
+
|
|
+ /* add enable 325M clock for SGMII */
|
|
+ mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
|
|
+
|
|
+ /* add enable 250SSC clock for RGMII */
|
|
+ mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
|
|
+
|
|
+ /*Step 6: Enable MT7531 PLL */
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
|
|
+
|
|
+ mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
|
|
+
|
|
+ udelay(25);
|
|
+}
|
|
+
|
|
+static int mt7531_port_sgmii_init(struct mt753x_switch_priv *priv, u32 port)
|
|
+{
|
|
+ if (port != 5 && port != 6) {
|
|
+ printf("mt7531: port %d is not a SGMII port\n", port);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Set SGMII GEN2 speed(2.5G) */
|
|
+ mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
|
|
+ FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
|
|
+
|
|
+ /* Disable SGMII AN */
|
|
+ mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
|
|
+ SGMII_AN_ENABLE, 0);
|
|
+
|
|
+ /* SGMII force mode setting */
|
|
+ mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
|
|
+
|
|
+ /* Release PHYA power down state */
|
|
+ mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
|
|
+ SGMII_PHYA_PWD, 0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt7531_port_rgmii_init(struct mt753x_switch_priv *priv, u32 port)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ if (port != 5) {
|
|
+ printf("error: RGMII mode is not available for port %d\n",
|
|
+ port);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
|
|
+ val |= GP_CLK_EN;
|
|
+ val &= ~GP_MODE_M;
|
|
+ val |= GP_MODE_RGMII << GP_MODE_S;
|
|
+ val |= TXCLK_NO_REVERSE;
|
|
+ val |= RXCLK_NO_DELAY;
|
|
+ val &= ~CLK_SKEW_IN_M;
|
|
+ val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
|
|
+ val &= ~CLK_SKEW_OUT_M;
|
|
+ val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
|
|
+ mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mt7531_phy_setting(struct mt753x_switch_priv *priv)
|
|
+{
|
|
+ int i;
|
|
+ u32 val;
|
|
+
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ /* Enable HW auto downshift */
|
|
+ mt7531_mii_write(priv, i, 0x1f, 0x1);
|
|
+ val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
|
|
+ val |= PHY_EN_DOWN_SHFIT;
|
|
+ mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
|
|
+
|
|
+ /* PHY link down power saving enable */
|
|
+ val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
|
|
+ val |= PHY_LINKDOWN_POWER_SAVING_EN;
|
|
+ mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
|
|
+
|
|
+ val = mt7531_mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
|
|
+ val &= ~PHY_POWER_SAVING_M;
|
|
+ val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
|
|
+ mt7531_mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void mt7531_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+ u32 pmcr = FORCE_MODE_LNK;
|
|
+
|
|
+ if (enable)
|
|
+ pmcr = priv->pmcr;
|
|
+
|
|
+ mt753x_reg_write(priv, PMCR_REG(5), pmcr);
|
|
+ mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
|
+}
|
|
+
|
|
+static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+ u32 i, val, pmcr, port5_sgmii;
|
|
+ u16 phy_addr, phy_val;
|
|
+
|
|
+ priv->smi_addr = MT753X_DFL_SMI_ADDR;
|
|
+ priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
|
|
+ priv->reg_read = mt753x_mdio_reg_read;
|
|
+ priv->reg_write = mt753x_mdio_reg_write;
|
|
+
|
|
+ /* Turn off PHYs */
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
|
+ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
|
+ phy_val |= BMCR_PDOWN;
|
|
+ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
+ }
|
|
+
|
|
+ /* Force MAC link down before reset */
|
|
+ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
|
|
+ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
|
+
|
|
+ /* Switch soft reset */
|
|
+ mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
|
|
+ udelay(100);
|
|
+
|
|
+ /* Enable MDC input Schmitt Trigger */
|
|
+ mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
|
|
+ SMT_IOLB_5_SMI_MDC_EN);
|
|
+
|
|
+ mt7531_core_pll_setup(priv);
|
|
+
|
|
+ mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
|
|
+ port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
|
|
+
|
|
+ /* port5 support either RGMII or SGMII, port6 only support SGMII. */
|
|
+ switch (priv->epriv.phy_interface) {
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ if (!port5_sgmii)
|
|
+ mt7531_port_rgmii_init(priv, 5);
|
|
+ break;
|
|
+
|
|
+ case PHY_INTERFACE_MODE_2500BASEX:
|
|
+ mt7531_port_sgmii_init(priv, 6);
|
|
+ if (port5_sgmii)
|
|
+ mt7531_port_sgmii_init(priv, 5);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ pmcr = MT7531_FORCE_MODE |
|
|
+ (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
+ MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
|
+ BKOFF_EN | BACKPR_EN |
|
|
+ FORCE_RX_FC | FORCE_TX_FC |
|
|
+ (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
|
|
+ FORCE_LINK;
|
|
+
|
|
+ priv->pmcr = pmcr;
|
|
+
|
|
+ /* Keep MAC link down before starting eth */
|
|
+ mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
|
|
+ mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
|
+
|
|
+ /* Enable port isolation to block inter-port communication */
|
|
+ mt753x_port_isolation(priv);
|
|
+
|
|
+ /* Turn on PHYs */
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
|
+ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
|
+ phy_val &= ~BMCR_PDOWN;
|
|
+ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
+ }
|
|
+
|
|
+ mt7531_phy_setting(priv);
|
|
+
|
|
+ /* Enable Internal PHYs */
|
|
+ val = mt7531_core_reg_read(priv, CORE_PLL_GROUP4);
|
|
+ val |= MT7531_BYPASS_MODE;
|
|
+ val &= ~MT7531_POWER_ON_OFF;
|
|
+ mt7531_core_reg_write(priv, CORE_PLL_GROUP4, val);
|
|
+
|
|
+ return mt7531_mdio_register(priv);
|
|
+}
|
|
+
|
|
+static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+
|
|
+ mdio_unregister(priv->mdio_bus);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt7531_detect(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ int ret;
|
|
+ u32 rev;
|
|
+
|
|
+ ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7531)
|
|
+ return 0;
|
|
+
|
|
+ return -ENODEV;
|
|
+}
|
|
+
|
|
+MTK_ETH_SWITCH(mt7531) = {
|
|
+ .name = "mt7531",
|
|
+ .desc = "MediaTek MT7531",
|
|
+ .priv_size = sizeof(struct mt753x_switch_priv),
|
|
+ .reset_wait_time = 200,
|
|
+
|
|
+ .detect = mt7531_detect,
|
|
+ .setup = mt7531_setup,
|
|
+ .cleanup = mt7531_cleanup,
|
|
+ .mac_control = mt7531_mac_control,
|
|
+};
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mt753x.c
|
|
@@ -0,0 +1,262 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#include <errno.h>
|
|
+#include <time.h>
|
|
+#include "mtk_eth.h"
|
|
+#include "mt753x.h"
|
|
+
|
|
+/*
|
|
+ * MT753x Internal Register Address Bits
|
|
+ * -------------------------------------------------------------------
|
|
+ * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 |
|
|
+ * |----------------------------------------|---------------|--------|
|
|
+ * | Page Address | Reg Address | Unused |
|
|
+ * -------------------------------------------------------------------
|
|
+ */
|
|
+
|
|
+int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
|
|
+ u32 *data)
|
|
+{
|
|
+ int ret, low_word, high_word;
|
|
+
|
|
+ /* Write page address */
|
|
+ ret = mtk_mii_write(priv, smi_addr, 0x1f, reg >> 6);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Read low word */
|
|
+ low_word = mtk_mii_read(priv, smi_addr, (reg >> 2) & 0xf);
|
|
+ if (low_word < 0)
|
|
+ return low_word;
|
|
+
|
|
+ /* Read high word */
|
|
+ high_word = mtk_mii_read(priv, smi_addr, 0x10);
|
|
+ if (high_word < 0)
|
|
+ return high_word;
|
|
+
|
|
+ if (data)
|
|
+ *data = ((u32)high_word << 16) | (low_word & 0xffff);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
|
|
+{
|
|
+ return __mt753x_mdio_reg_read(priv->epriv.eth, priv->smi_addr, reg,
|
|
+ data);
|
|
+}
|
|
+
|
|
+int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ /* Write page address */
|
|
+ ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x1f, reg >> 6);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Write low word */
|
|
+ ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, (reg >> 2) & 0xf,
|
|
+ data & 0xffff);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Write high word */
|
|
+ return mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x10, data >> 16);
|
|
+}
|
|
+
|
|
+int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
|
|
+{
|
|
+ return priv->reg_read(priv, reg, data);
|
|
+}
|
|
+
|
|
+int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
|
|
+{
|
|
+ return priv->reg_write(priv, reg, data);
|
|
+}
|
|
+
|
|
+void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set)
|
|
+{
|
|
+ u32 val;
|
|
+
|
|
+ priv->reg_read(priv, reg, &val);
|
|
+ val &= ~clr;
|
|
+ val |= set;
|
|
+ priv->reg_write(priv, reg, val);
|
|
+}
|
|
+
|
|
+/* Indirect MDIO clause 22/45 access */
|
|
+static int mt7531_mii_rw(struct mt753x_switch_priv *priv, int phy, int reg,
|
|
+ u16 data, u32 cmd, u32 st)
|
|
+{
|
|
+ u32 val, timeout_ms;
|
|
+ ulong timeout;
|
|
+ int ret = 0;
|
|
+
|
|
+ val = (st << MDIO_ST_S) |
|
|
+ ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
|
|
+ ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
|
|
+ ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
|
|
+
|
|
+ if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
|
|
+ val |= data & MDIO_RW_DATA_M;
|
|
+
|
|
+ mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
|
|
+
|
|
+ timeout_ms = 100;
|
|
+ timeout = get_timer(0);
|
|
+ while (1) {
|
|
+ mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
|
|
+
|
|
+ if ((val & PHY_ACS_ST) == 0)
|
|
+ break;
|
|
+
|
|
+ if (get_timer(timeout) > timeout_ms)
|
|
+ return -ETIMEDOUT;
|
|
+ }
|
|
+
|
|
+ if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
|
|
+ mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
|
|
+ ret = val & MDIO_RW_DATA_M;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg)
|
|
+{
|
|
+ u8 phy_addr;
|
|
+
|
|
+ if (phy >= MT753X_NUM_PHYS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
|
|
+
|
|
+ return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
|
|
+ MDIO_ST_C22);
|
|
+}
|
|
+
|
|
+int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val)
|
|
+{
|
|
+ u8 phy_addr;
|
|
+
|
|
+ if (phy >= MT753X_NUM_PHYS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
|
|
+
|
|
+ return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
|
|
+ MDIO_ST_C22);
|
|
+}
|
|
+
|
|
+int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
|
+ u16 reg)
|
|
+{
|
|
+ u8 phy_addr;
|
|
+ int ret;
|
|
+
|
|
+ if (addr >= MT753X_NUM_PHYS)
|
|
+ return -EINVAL;
|
|
+
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
|
|
+
|
|
+ ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
|
|
+ MDIO_ST_C45);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
|
|
+ MDIO_ST_C45);
|
|
+}
|
|
+
|
|
+int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
|
+ u16 reg, u16 val)
|
|
+{
|
|
+ u8 phy_addr;
|
|
+ int ret;
|
|
+
|
|
+ if (addr >= MT753X_NUM_PHYS)
|
|
+ return 0;
|
|
+
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
|
|
+
|
|
+ ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
|
|
+ MDIO_ST_C45);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
|
|
+ MDIO_ST_C45);
|
|
+}
|
|
+
|
|
+static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = bus->priv;
|
|
+
|
|
+ if (devad < 0)
|
|
+ return mt7531_mii_read(priv, addr, reg);
|
|
+
|
|
+ return mt7531_mmd_read(priv, addr, devad, reg);
|
|
+}
|
|
+
|
|
+static int mt7531_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
|
+ u16 val)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = bus->priv;
|
|
+
|
|
+ if (devad < 0)
|
|
+ return mt7531_mii_write(priv, addr, reg, val);
|
|
+
|
|
+ return mt7531_mmd_write(priv, addr, devad, reg, val);
|
|
+}
|
|
+
|
|
+int mt7531_mdio_register(struct mt753x_switch_priv *priv)
|
|
+{
|
|
+ struct mii_dev *mdio_bus = mdio_alloc();
|
|
+ int ret;
|
|
+
|
|
+ if (!mdio_bus)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ mdio_bus->read = mt7531_mdio_read;
|
|
+ mdio_bus->write = mt7531_mdio_write;
|
|
+ snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
|
|
+
|
|
+ mdio_bus->priv = priv;
|
|
+
|
|
+ ret = mdio_register(mdio_bus);
|
|
+ if (ret) {
|
|
+ mdio_free(mdio_bus);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ priv->mdio_bus = mdio_bus;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void mt753x_port_isolation(struct mt753x_switch_priv *priv)
|
|
+{
|
|
+ u32 i;
|
|
+
|
|
+ for (i = 0; i < MT753X_NUM_PORTS; i++) {
|
|
+ /* Set port matrix mode */
|
|
+ if (i != 6)
|
|
+ mt753x_reg_write(priv, PCR_REG(i),
|
|
+ (0x40 << PORT_MATRIX_S));
|
|
+ else
|
|
+ mt753x_reg_write(priv, PCR_REG(i),
|
|
+ (0x3f << PORT_MATRIX_S));
|
|
+
|
|
+ /* Set port mode to user port */
|
|
+ mt753x_reg_write(priv, PVC_REG(i),
|
|
+ (0x8100 << STAG_VPID_S) |
|
|
+ (VLAN_ATTR_USER << VLAN_ATTR_S));
|
|
+ }
|
|
+}
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mt753x.h
|
|
@@ -0,0 +1,286 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#ifndef _MTK_ETH_MT753X_H_
|
|
+#define _MTK_ETH_MT753X_H_
|
|
+
|
|
+#include <phy.h>
|
|
+#include <miiphy.h>
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/bitfield.h>
|
|
+
|
|
+struct mtk_eth_priv;
|
|
+
|
|
+#define MT753X_NUM_PHYS 5
|
|
+#define MT753X_NUM_PORTS 7
|
|
+#define MT753X_DFL_SMI_ADDR 31
|
|
+#define MT753X_SMI_ADDR_MASK 0x1f
|
|
+
|
|
+#define MT753X_PHY_ADDR(base, addr) \
|
|
+ (((base) + (addr)) & 0x1f)
|
|
+
|
|
+/* MT7530 Registers */
|
|
+#define PCR_REG(p) (0x2004 + (p) * 0x100)
|
|
+#define PORT_MATRIX_S 16
|
|
+#define PORT_MATRIX_M 0xff0000
|
|
+
|
|
+#define PVC_REG(p) (0x2010 + (p) * 0x100)
|
|
+#define STAG_VPID_S 16
|
|
+#define STAG_VPID_M 0xffff0000
|
|
+#define VLAN_ATTR_S 6
|
|
+#define VLAN_ATTR_M 0xc0
|
|
+
|
|
+/* VLAN_ATTR: VLAN attributes */
|
|
+#define VLAN_ATTR_USER 0
|
|
+#define VLAN_ATTR_STACK 1
|
|
+#define VLAN_ATTR_TRANSLATION 2
|
|
+#define VLAN_ATTR_TRANSPARENT 3
|
|
+
|
|
+#define PMCR_REG(p) (0x3000 + (p) * 0x100)
|
|
+/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
|
|
+ * MT7531 specific fields are defined below
|
|
+ */
|
|
+#define FORCE_MODE_EEE1G BIT(25)
|
|
+#define FORCE_MODE_EEE100 BIT(26)
|
|
+#define FORCE_MODE_TX_FC BIT(27)
|
|
+#define FORCE_MODE_RX_FC BIT(28)
|
|
+#define FORCE_MODE_DPX BIT(29)
|
|
+#define FORCE_MODE_SPD BIT(30)
|
|
+#define FORCE_MODE_LNK BIT(31)
|
|
+#define MT7531_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
|
|
+ FORCE_MODE_DPX | FORCE_MODE_SPD | \
|
|
+ FORCE_MODE_LNK
|
|
+#define MT7988_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
|
|
+ FORCE_MODE_DPX | FORCE_MODE_SPD | \
|
|
+ FORCE_MODE_LNK
|
|
+
|
|
+/* MT7531 SGMII Registers */
|
|
+#define MT7531_SGMII_REG_BASE 0x5000
|
|
+#define MT7531_SGMII_REG_PORT_BASE 0x1000
|
|
+#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \
|
|
+ (p) * MT7531_SGMII_REG_PORT_BASE + (r))
|
|
+#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(((p) - 5), 0x00)
|
|
+#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(((p) - 5), 0x20)
|
|
+#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8)
|
|
+#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(((p) - 5), 0x128)
|
|
+#define MT7531_PHYA_ANA_SYSPLL(p) MT7531_SGMII_REG(((p) - 5), 0x158)
|
|
+/* XXX: all fields of MT7531 SGMII are defined under SGMSYS */
|
|
+
|
|
+/* MT753x System Control Register */
|
|
+#define SYS_CTRL_REG 0x7000
|
|
+#define SW_PHY_RST BIT(2)
|
|
+#define SW_SYS_RST BIT(1)
|
|
+#define SW_REG_RST BIT(0)
|
|
+
|
|
+/* MT7531 */
|
|
+#define MT7531_PHY_IAC 0x701c
|
|
+/* XXX: all fields are defined under GMAC_PIAC_REG */
|
|
+
|
|
+#define MT7531_CLKGEN_CTRL 0x7500
|
|
+#define CLK_SKEW_OUT_S 8
|
|
+#define CLK_SKEW_OUT_M 0x300
|
|
+#define CLK_SKEW_IN_S 6
|
|
+#define CLK_SKEW_IN_M 0xc0
|
|
+#define RXCLK_NO_DELAY BIT(5)
|
|
+#define TXCLK_NO_REVERSE BIT(4)
|
|
+#define GP_MODE_S 1
|
|
+#define GP_MODE_M 0x06
|
|
+#define GP_CLK_EN BIT(0)
|
|
+
|
|
+/* Values of GP_MODE */
|
|
+#define GP_MODE_RGMII 0
|
|
+#define GP_MODE_MII 1
|
|
+#define GP_MODE_REV_MII 2
|
|
+
|
|
+/* Values of CLK_SKEW_IN */
|
|
+#define CLK_SKEW_IN_NO_CHANGE 0
|
|
+#define CLK_SKEW_IN_DELAY_100PPS 1
|
|
+#define CLK_SKEW_IN_DELAY_200PPS 2
|
|
+#define CLK_SKEW_IN_REVERSE 3
|
|
+
|
|
+/* Values of CLK_SKEW_OUT */
|
|
+#define CLK_SKEW_OUT_NO_CHANGE 0
|
|
+#define CLK_SKEW_OUT_DELAY_100PPS 1
|
|
+#define CLK_SKEW_OUT_DELAY_200PPS 2
|
|
+#define CLK_SKEW_OUT_REVERSE 3
|
|
+
|
|
+#define HWTRAP_REG 0x7800
|
|
+/* MT7530 Modified Hardware Trap Status Registers */
|
|
+#define MHWTRAP_REG 0x7804
|
|
+#define CHG_TRAP BIT(16)
|
|
+#define LOOPDET_DIS BIT(14)
|
|
+#define P5_INTF_SEL_S 13
|
|
+#define P5_INTF_SEL_M 0x2000
|
|
+#define SMI_ADDR_S 11
|
|
+#define SMI_ADDR_M 0x1800
|
|
+#define XTAL_FSEL_S 9
|
|
+#define XTAL_FSEL_M 0x600
|
|
+#define P6_INTF_DIS BIT(8)
|
|
+#define P5_INTF_MODE_S 7
|
|
+#define P5_INTF_MODE_M 0x80
|
|
+#define P5_INTF_DIS BIT(6)
|
|
+#define C_MDIO_BPS BIT(5)
|
|
+#define CHIP_MODE_S 0
|
|
+#define CHIP_MODE_M 0x0f
|
|
+
|
|
+/* P5_INTF_SEL: Interface type of Port5 */
|
|
+#define P5_INTF_SEL_GPHY 0
|
|
+#define P5_INTF_SEL_GMAC5 1
|
|
+
|
|
+/* P5_INTF_MODE: Interface mode of Port5 */
|
|
+#define P5_INTF_MODE_GMII_MII 0
|
|
+#define P5_INTF_MODE_RGMII 1
|
|
+
|
|
+#define MT7530_P6ECR 0x7830
|
|
+#define P6_INTF_MODE_M 0x3
|
|
+#define P6_INTF_MODE_S 0
|
|
+
|
|
+/* P6_INTF_MODE: Interface mode of Port6 */
|
|
+#define P6_INTF_MODE_RGMII 0
|
|
+#define P6_INTF_MODE_TRGMII 1
|
|
+
|
|
+#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8)
|
|
+#define RD_TAP_S 0
|
|
+#define RD_TAP_M 0x7f
|
|
+
|
|
+#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8)
|
|
+/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
|
|
+
|
|
+/* TOP Signals Status Register */
|
|
+#define MT7531_TOP_SIG_SR 0x780c
|
|
+#define PAD_MCM_SMI_EN BIT(0)
|
|
+#define PAD_DUAL_SGMII_EN BIT(1)
|
|
+
|
|
+/* MT7531 PLLGP Registers */
|
|
+#define MT7531_PLLGP_EN 0x7820
|
|
+#define EN_COREPLL BIT(2)
|
|
+#define SW_CLKSW BIT(1)
|
|
+#define SW_PLLGP BIT(0)
|
|
+
|
|
+#define MT7531_PLLGP_CR0 0x78a8
|
|
+#define RG_COREPLL_EN BIT(22)
|
|
+#define RG_COREPLL_POSDIV_S 23
|
|
+#define RG_COREPLL_POSDIV_M 0x3800000
|
|
+#define RG_COREPLL_SDM_PCW_S 1
|
|
+#define RG_COREPLL_SDM_PCW_M 0x3ffffe
|
|
+#define RG_COREPLL_SDM_PCW_CHG BIT(0)
|
|
+
|
|
+/* MT7531 RGMII and SGMII PLL clock */
|
|
+#define MT7531_ANA_PLLGP_CR2 0x78b0
|
|
+#define MT7531_ANA_PLLGP_CR5 0x78bc
|
|
+
|
|
+/* MT7531 GPIO GROUP IOLB SMT0 Control */
|
|
+#define MT7531_SMT0_IOLB 0x7f04
|
|
+#define SMT_IOLB_5_SMI_MDC_EN BIT(5)
|
|
+
|
|
+/* MT7530 GPHY MDIO MMD Registers */
|
|
+#define CORE_PLL_GROUP2 0x401
|
|
+#define RG_SYSPLL_EN_NORMAL BIT(15)
|
|
+#define RG_SYSPLL_VODEN BIT(14)
|
|
+#define RG_SYSPLL_POSDIV_S 5
|
|
+#define RG_SYSPLL_POSDIV_M 0x60
|
|
+
|
|
+#define CORE_PLL_GROUP4 0x403
|
|
+#define MT7531_BYPASS_MODE BIT(4)
|
|
+#define MT7531_POWER_ON_OFF BIT(5)
|
|
+#define RG_SYSPLL_DDSFBK_EN BIT(12)
|
|
+#define RG_SYSPLL_BIAS_EN BIT(11)
|
|
+#define RG_SYSPLL_BIAS_LPF_EN BIT(10)
|
|
+
|
|
+#define CORE_PLL_GROUP5 0x404
|
|
+#define RG_LCDDS_PCW_NCPO1_S 0
|
|
+#define RG_LCDDS_PCW_NCPO1_M 0xffff
|
|
+
|
|
+#define CORE_PLL_GROUP6 0x405
|
|
+#define RG_LCDDS_PCW_NCPO0_S 0
|
|
+#define RG_LCDDS_PCW_NCPO0_M 0xffff
|
|
+
|
|
+#define CORE_PLL_GROUP7 0x406
|
|
+#define RG_LCDDS_PWDB BIT(15)
|
|
+#define RG_LCDDS_ISO_EN BIT(13)
|
|
+#define RG_LCCDS_C_S 4
|
|
+#define RG_LCCDS_C_M 0x70
|
|
+#define RG_LCDDS_PCW_NCPO_CHG BIT(3)
|
|
+
|
|
+#define CORE_PLL_GROUP10 0x409
|
|
+#define RG_LCDDS_SSC_DELTA_S 0
|
|
+#define RG_LCDDS_SSC_DELTA_M 0xfff
|
|
+
|
|
+#define CORE_PLL_GROUP11 0x40a
|
|
+#define RG_LCDDS_SSC_DELTA1_S 0
|
|
+#define RG_LCDDS_SSC_DELTA1_M 0xfff
|
|
+
|
|
+#define CORE_GSWPLL_GRP1 0x40d
|
|
+#define RG_GSWPLL_POSDIV_200M_S 12
|
|
+#define RG_GSWPLL_POSDIV_200M_M 0x3000
|
|
+#define RG_GSWPLL_EN_PRE BIT(11)
|
|
+#define RG_GSWPLL_FBKDIV_200M_S 0
|
|
+#define RG_GSWPLL_FBKDIV_200M_M 0xff
|
|
+
|
|
+#define CORE_GSWPLL_GRP2 0x40e
|
|
+#define RG_GSWPLL_POSDIV_500M_S 8
|
|
+#define RG_GSWPLL_POSDIV_500M_M 0x300
|
|
+#define RG_GSWPLL_FBKDIV_500M_S 0
|
|
+#define RG_GSWPLL_FBKDIV_500M_M 0xff
|
|
+
|
|
+#define CORE_TRGMII_GSW_CLK_CG 0x410
|
|
+#define REG_GSWCK_EN BIT(0)
|
|
+#define REG_TRGMIICK_EN BIT(1)
|
|
+
|
|
+/* Extend PHY Control Register 3 */
|
|
+#define PHY_EXT_REG_14 0x14
|
|
+
|
|
+/* Fields of PHY_EXT_REG_14 */
|
|
+#define PHY_EN_DOWN_SHFIT BIT(4)
|
|
+
|
|
+/* Extend PHY Control Register 4 */
|
|
+#define PHY_EXT_REG_17 0x17
|
|
+
|
|
+/* Fields of PHY_EXT_REG_17 */
|
|
+#define PHY_LINKDOWN_POWER_SAVING_EN BIT(4)
|
|
+
|
|
+/* PHY RXADC Control Register 7 */
|
|
+#define PHY_DEV1E_REG_0C6 0x0c6
|
|
+
|
|
+/* Fields of PHY_DEV1E_REG_0C6 */
|
|
+#define PHY_POWER_SAVING_S 8
|
|
+#define PHY_POWER_SAVING_M 0x300
|
|
+#define PHY_POWER_SAVING_TX 0x0
|
|
+
|
|
+struct mt753x_switch_priv {
|
|
+ struct mtk_eth_switch_priv epriv;
|
|
+ struct mii_dev *mdio_bus;
|
|
+ u32 smi_addr;
|
|
+ u32 phy_base;
|
|
+ u32 pmcr;
|
|
+
|
|
+ int (*reg_read)(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
|
|
+ int (*reg_write)(struct mt753x_switch_priv *priv, u32 reg, u32 data);
|
|
+};
|
|
+
|
|
+int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
|
|
+ u32 *data);
|
|
+int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
|
|
+int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
|
|
+
|
|
+int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
|
|
+int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
|
|
+void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set);
|
|
+
|
|
+int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg);
|
|
+int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val);
|
|
+int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
|
+ u16 reg);
|
|
+int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
|
+ u16 reg, u16 val);
|
|
+
|
|
+int mt7531_mdio_register(struct mt753x_switch_priv *priv);
|
|
+
|
|
+void mt753x_port_isolation(struct mt753x_switch_priv *priv);
|
|
+
|
|
+#endif /* _MTK_ETH_MT753X_H_ */
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mt7988.c
|
|
@@ -0,0 +1,160 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#include <miiphy.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/mdio.h>
|
|
+#include <linux/mii.h>
|
|
+#include <linux/io.h>
|
|
+#include "mtk_eth.h"
|
|
+#include "mt753x.h"
|
|
+
|
|
+static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
|
|
+{
|
|
+ *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
|
|
+{
|
|
+ writel(data, priv->epriv.ethsys_base + GSW_BASE + reg);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mt7988_phy_setting(struct mt753x_switch_priv *priv)
|
|
+{
|
|
+ u16 val;
|
|
+ u32 i;
|
|
+
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ /* Enable HW auto downshift */
|
|
+ mt7531_mii_write(priv, i, 0x1f, 0x1);
|
|
+ val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
|
|
+ val |= PHY_EN_DOWN_SHFIT;
|
|
+ mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
|
|
+
|
|
+ /* PHY link down power saving enable */
|
|
+ val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
|
|
+ val |= PHY_LINKDOWN_POWER_SAVING_EN;
|
|
+ mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+ u32 pmcr = FORCE_MODE_LNK;
|
|
+
|
|
+ if (enable)
|
|
+ pmcr = priv->pmcr;
|
|
+
|
|
+ mt7988_reg_write(priv, PMCR_REG(6), pmcr);
|
|
+}
|
|
+
|
|
+static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+ u16 phy_addr, phy_val;
|
|
+ u32 pmcr;
|
|
+ int i;
|
|
+
|
|
+ priv->smi_addr = MT753X_DFL_SMI_ADDR;
|
|
+ priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
|
|
+ priv->reg_read = mt7988_reg_read;
|
|
+ priv->reg_write = mt7988_reg_write;
|
|
+
|
|
+ /* Turn off PHYs */
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
|
+ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
|
+ phy_val |= BMCR_PDOWN;
|
|
+ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
+ }
|
|
+
|
|
+ switch (priv->epriv.phy_interface) {
|
|
+ case PHY_INTERFACE_MODE_USXGMII:
|
|
+ /* Use CPU bridge instead of actual USXGMII path */
|
|
+
|
|
+ /* Disable GDM1 RX CRC stripping */
|
|
+ /* mtk_fe_rmw(priv, 0x500, BIT(16), 0); */
|
|
+
|
|
+ /* Set GDM1 no drop */
|
|
+ mtk_fe_rmw(priv->epriv.eth, PSE_NO_DROP_CFG_REG, 0,
|
|
+ PSE_NO_DROP_GDM1);
|
|
+
|
|
+ /* Enable GSW CPU bridge as USXGMII */
|
|
+ /* mtk_fe_rmw(priv, 0x504, BIT(31), BIT(31)); */
|
|
+
|
|
+ /* Enable GDM1 to GSW CPU bridge */
|
|
+ mtk_gmac_rmw(priv->epriv.eth, GMAC_MAC_MISC_REG, 0, BIT(0));
|
|
+
|
|
+ /* XGMAC force link up */
|
|
+ mtk_gmac_rmw(priv->epriv.eth, GMAC_XGMAC_STS_REG, 0,
|
|
+ P1_XGMAC_FORCE_LINK);
|
|
+
|
|
+ /* Setup GSW CPU bridge IPG */
|
|
+ mtk_gmac_rmw(priv->epriv.eth, GMAC_GSW_CFG_REG,
|
|
+ GSWTX_IPG_M | GSWRX_IPG_M,
|
|
+ (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
|
|
+ break;
|
|
+ default:
|
|
+ printf("Error: MT7988 GSW does not support %s interface\n",
|
|
+ phy_string_for_interface(priv->epriv.phy_interface));
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ pmcr = MT7988_FORCE_MODE |
|
|
+ (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
+ MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
|
+ BKOFF_EN | BACKPR_EN |
|
|
+ FORCE_RX_FC | FORCE_TX_FC |
|
|
+ (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
|
|
+ FORCE_LINK;
|
|
+
|
|
+ priv->pmcr = pmcr;
|
|
+
|
|
+ /* Keep MAC link down before starting eth */
|
|
+ mt7988_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
|
+
|
|
+ /* Enable port isolation to block inter-port communication */
|
|
+ mt753x_port_isolation(priv);
|
|
+
|
|
+ /* Turn on PHYs */
|
|
+ for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
+ phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
|
+ phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
|
+ phy_val &= ~BMCR_PDOWN;
|
|
+ mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
+ }
|
|
+
|
|
+ mt7988_phy_setting(priv);
|
|
+
|
|
+ return mt7531_mdio_register(priv);
|
|
+}
|
|
+
|
|
+static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
|
|
+{
|
|
+ struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
|
+
|
|
+ mdio_unregister(priv->mdio_bus);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+MTK_ETH_SWITCH(mt7988) = {
|
|
+ .name = "mt7988",
|
|
+ .desc = "MediaTek MT7988 built-in switch",
|
|
+ .priv_size = sizeof(struct mt753x_switch_priv),
|
|
+ .reset_wait_time = 50,
|
|
+
|
|
+ .setup = mt7988_setup,
|
|
+ .cleanup = mt7531_cleanup,
|
|
+ .mac_control = mt7988_mac_control,
|
|
+};
|
|
--- a/drivers/net/mtk_eth.c
|
|
+++ /dev/null
|
|
@@ -1,2280 +0,0 @@
|
|
-// SPDX-License-Identifier: GPL-2.0
|
|
-/*
|
|
- * Copyright (C) 2018 MediaTek Inc.
|
|
- *
|
|
- * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
- * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
- */
|
|
-
|
|
-#include <cpu_func.h>
|
|
-#include <dm.h>
|
|
-#include <log.h>
|
|
-#include <malloc.h>
|
|
-#include <miiphy.h>
|
|
-#include <net.h>
|
|
-#include <regmap.h>
|
|
-#include <reset.h>
|
|
-#include <syscon.h>
|
|
-#include <wait_bit.h>
|
|
-#include <asm/cache.h>
|
|
-#include <asm/gpio.h>
|
|
-#include <asm/io.h>
|
|
-#include <dm/device_compat.h>
|
|
-#include <linux/delay.h>
|
|
-#include <linux/err.h>
|
|
-#include <linux/ioport.h>
|
|
-#include <linux/mdio.h>
|
|
-#include <linux/mii.h>
|
|
-#include <linux/printk.h>
|
|
-
|
|
-#include "mtk_eth.h"
|
|
-
|
|
-#define NUM_TX_DESC 32
|
|
-#define NUM_RX_DESC 32
|
|
-#define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN)
|
|
-#define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN)
|
|
-#define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
|
|
-
|
|
-#define MT753X_NUM_PHYS 5
|
|
-#define MT753X_NUM_PORTS 7
|
|
-#define MT753X_DFL_SMI_ADDR 31
|
|
-#define MT753X_SMI_ADDR_MASK 0x1f
|
|
-
|
|
-#define MT753X_PHY_ADDR(base, addr) \
|
|
- (((base) + (addr)) & 0x1f)
|
|
-
|
|
-#define GDMA_FWD_TO_CPU \
|
|
- (0x20000000 | \
|
|
- GDM_ICS_EN | \
|
|
- GDM_TCS_EN | \
|
|
- GDM_UCS_EN | \
|
|
- STRP_CRC | \
|
|
- (DP_PDMA << MYMAC_DP_S) | \
|
|
- (DP_PDMA << BC_DP_S) | \
|
|
- (DP_PDMA << MC_DP_S) | \
|
|
- (DP_PDMA << UN_DP_S))
|
|
-
|
|
-#define GDMA_BRIDGE_TO_CPU \
|
|
- (0xC0000000 | \
|
|
- GDM_ICS_EN | \
|
|
- GDM_TCS_EN | \
|
|
- GDM_UCS_EN | \
|
|
- (DP_PDMA << MYMAC_DP_S) | \
|
|
- (DP_PDMA << BC_DP_S) | \
|
|
- (DP_PDMA << MC_DP_S) | \
|
|
- (DP_PDMA << UN_DP_S))
|
|
-
|
|
-#define GDMA_FWD_DISCARD \
|
|
- (0x20000000 | \
|
|
- GDM_ICS_EN | \
|
|
- GDM_TCS_EN | \
|
|
- GDM_UCS_EN | \
|
|
- STRP_CRC | \
|
|
- (DP_DISCARD << MYMAC_DP_S) | \
|
|
- (DP_DISCARD << BC_DP_S) | \
|
|
- (DP_DISCARD << MC_DP_S) | \
|
|
- (DP_DISCARD << UN_DP_S))
|
|
-
|
|
-enum mtk_switch {
|
|
- SW_NONE,
|
|
- SW_MT7530,
|
|
- SW_MT7531,
|
|
- SW_MT7988,
|
|
-};
|
|
-
|
|
-/* struct mtk_soc_data - This is the structure holding all differences
|
|
- * among various plaforms
|
|
- * @caps Flags shown the extra capability for the SoC
|
|
- * @ana_rgc3: The offset for register ANA_RGC3 related to
|
|
- * sgmiisys syscon
|
|
- * @gdma_count: Number of GDMAs
|
|
- * @pdma_base: Register base of PDMA block
|
|
- * @txd_size: Tx DMA descriptor size.
|
|
- * @rxd_size: Rx DMA descriptor size.
|
|
- */
|
|
-struct mtk_soc_data {
|
|
- u32 caps;
|
|
- u32 ana_rgc3;
|
|
- u32 gdma_count;
|
|
- u32 pdma_base;
|
|
- u32 txd_size;
|
|
- u32 rxd_size;
|
|
-};
|
|
-
|
|
-struct mtk_eth_priv {
|
|
- char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
|
|
-
|
|
- void *tx_ring_noc;
|
|
- void *rx_ring_noc;
|
|
-
|
|
- int rx_dma_owner_idx0;
|
|
- int tx_cpu_owner_idx0;
|
|
-
|
|
- void __iomem *fe_base;
|
|
- void __iomem *gmac_base;
|
|
- void __iomem *sgmii_base;
|
|
- void __iomem *gsw_base;
|
|
-
|
|
- struct regmap *ethsys_regmap;
|
|
-
|
|
- struct regmap *infra_regmap;
|
|
-
|
|
- struct regmap *usxgmii_regmap;
|
|
- struct regmap *xfi_pextp_regmap;
|
|
- struct regmap *xfi_pll_regmap;
|
|
- struct regmap *toprgu_regmap;
|
|
-
|
|
- struct mii_dev *mdio_bus;
|
|
- int (*mii_read)(struct mtk_eth_priv *priv, u8 phy, u8 reg);
|
|
- int (*mii_write)(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 val);
|
|
- int (*mmd_read)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
|
|
- int (*mmd_write)(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
|
|
- u16 val);
|
|
-
|
|
- const struct mtk_soc_data *soc;
|
|
- int gmac_id;
|
|
- int force_mode;
|
|
- int speed;
|
|
- int duplex;
|
|
- int mdc;
|
|
- bool pn_swap;
|
|
-
|
|
- struct phy_device *phydev;
|
|
- int phy_interface;
|
|
- int phy_addr;
|
|
-
|
|
- enum mtk_switch sw;
|
|
- int (*switch_init)(struct mtk_eth_priv *priv);
|
|
- void (*switch_mac_control)(struct mtk_eth_priv *priv, bool enable);
|
|
- u32 mt753x_smi_addr;
|
|
- u32 mt753x_phy_base;
|
|
- u32 mt753x_pmcr;
|
|
- u32 mt753x_reset_wait_time;
|
|
-
|
|
- struct gpio_desc rst_gpio;
|
|
- int mcm;
|
|
-
|
|
- struct reset_ctl rst_fe;
|
|
- struct reset_ctl rst_mcm;
|
|
-};
|
|
-
|
|
-static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
|
|
-{
|
|
- writel(val, priv->fe_base + priv->soc->pdma_base + reg);
|
|
-}
|
|
-
|
|
-static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
|
|
- u32 set)
|
|
-{
|
|
- clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
|
|
-}
|
|
-
|
|
-static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
|
|
- u32 val)
|
|
-{
|
|
- u32 gdma_base;
|
|
-
|
|
- if (no == 2)
|
|
- gdma_base = GDMA3_BASE;
|
|
- else if (no == 1)
|
|
- gdma_base = GDMA2_BASE;
|
|
- else
|
|
- gdma_base = GDMA1_BASE;
|
|
-
|
|
- writel(val, priv->fe_base + gdma_base + reg);
|
|
-}
|
|
-
|
|
-static void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
|
|
-{
|
|
- clrsetbits_le32(priv->fe_base + reg, clr, set);
|
|
-}
|
|
-
|
|
-static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg)
|
|
-{
|
|
- return readl(priv->gmac_base + reg);
|
|
-}
|
|
-
|
|
-static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
|
|
-{
|
|
- writel(val, priv->gmac_base + reg);
|
|
-}
|
|
-
|
|
-static void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
|
|
-{
|
|
- clrsetbits_le32(priv->gmac_base + reg, clr, set);
|
|
-}
|
|
-
|
|
-static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
|
|
- u32 set)
|
|
-{
|
|
- uint val;
|
|
-
|
|
- regmap_read(priv->ethsys_regmap, reg, &val);
|
|
- val &= ~clr;
|
|
- val |= set;
|
|
- regmap_write(priv->ethsys_regmap, reg, val);
|
|
-}
|
|
-
|
|
-static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
|
|
- u32 set)
|
|
-{
|
|
- uint val;
|
|
-
|
|
- regmap_read(priv->infra_regmap, reg, &val);
|
|
- val &= ~clr;
|
|
- val |= set;
|
|
- regmap_write(priv->infra_regmap, reg, val);
|
|
-}
|
|
-
|
|
-static u32 mtk_gsw_read(struct mtk_eth_priv *priv, u32 reg)
|
|
-{
|
|
- return readl(priv->gsw_base + reg);
|
|
-}
|
|
-
|
|
-static void mtk_gsw_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
|
|
-{
|
|
- writel(val, priv->gsw_base + reg);
|
|
-}
|
|
-
|
|
-/* Direct MDIO clause 22/45 access via SoC */
|
|
-static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data,
|
|
- u32 cmd, u32 st)
|
|
-{
|
|
- int ret;
|
|
- u32 val;
|
|
-
|
|
- val = (st << MDIO_ST_S) |
|
|
- ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
|
|
- (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
|
|
- (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
|
|
-
|
|
- if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
|
|
- val |= data & MDIO_RW_DATA_M;
|
|
-
|
|
- mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST);
|
|
-
|
|
- ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG,
|
|
- PHY_ACS_ST, 0, 5000, 0);
|
|
- if (ret) {
|
|
- pr_warn("MDIO access timeout\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
- if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
|
|
- val = mtk_gmac_read(priv, GMAC_PIAC_REG);
|
|
- return val & MDIO_RW_DATA_M;
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-/* Direct MDIO clause 22 read via SoC */
|
|
-static int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
|
|
-{
|
|
- return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
|
|
-}
|
|
-
|
|
-/* Direct MDIO clause 22 write via SoC */
|
|
-static int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data)
|
|
-{
|
|
- return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22);
|
|
-}
|
|
-
|
|
-/* Direct MDIO clause 45 read via SoC */
|
|
-static int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45,
|
|
- MDIO_ST_C45);
|
|
-}
|
|
-
|
|
-/* Direct MDIO clause 45 write via SoC */
|
|
-static int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
|
|
- u16 reg, u16 val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE,
|
|
- MDIO_ST_C45);
|
|
-}
|
|
-
|
|
-/* Indirect MDIO clause 45 read via MII registers */
|
|
-static int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad,
|
|
- u16 reg)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
- (MMD_ADDR << MMD_CMD_S) |
|
|
- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
- (MMD_DATA << MMD_CMD_S) |
|
|
- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- return priv->mii_read(priv, addr, MII_MMD_ADDR_DATA_REG);
|
|
-}
|
|
-
|
|
-/* Indirect MDIO clause 45 write via MII registers */
|
|
-static int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
|
|
- u16 reg, u16 val)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
- (MMD_ADDR << MMD_CMD_S) |
|
|
- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- ret = priv->mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
- (MMD_DATA << MMD_CMD_S) |
|
|
- ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- return priv->mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val);
|
|
-}
|
|
-
|
|
-/*
|
|
- * MT7530 Internal Register Address Bits
|
|
- * -------------------------------------------------------------------
|
|
- * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 |
|
|
- * |----------------------------------------|---------------|--------|
|
|
- * | Page Address | Reg Address | Unused |
|
|
- * -------------------------------------------------------------------
|
|
- */
|
|
-
|
|
-static int mt753x_reg_read(struct mtk_eth_priv *priv, u32 reg, u32 *data)
|
|
-{
|
|
- int ret, low_word, high_word;
|
|
-
|
|
- if (priv->sw == SW_MT7988) {
|
|
- *data = mtk_gsw_read(priv, reg);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- /* Write page address */
|
|
- ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Read low word */
|
|
- low_word = mtk_mii_read(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf);
|
|
- if (low_word < 0)
|
|
- return low_word;
|
|
-
|
|
- /* Read high word */
|
|
- high_word = mtk_mii_read(priv, priv->mt753x_smi_addr, 0x10);
|
|
- if (high_word < 0)
|
|
- return high_word;
|
|
-
|
|
- if (data)
|
|
- *data = ((u32)high_word << 16) | (low_word & 0xffff);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mt753x_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 data)
|
|
-{
|
|
- int ret;
|
|
-
|
|
- if (priv->sw == SW_MT7988) {
|
|
- mtk_gsw_write(priv, reg, data);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- /* Write page address */
|
|
- ret = mtk_mii_write(priv, priv->mt753x_smi_addr, 0x1f, reg >> 6);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Write low word */
|
|
- ret = mtk_mii_write(priv, priv->mt753x_smi_addr, (reg >> 2) & 0xf,
|
|
- data & 0xffff);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Write high word */
|
|
- return mtk_mii_write(priv, priv->mt753x_smi_addr, 0x10, data >> 16);
|
|
-}
|
|
-
|
|
-static void mt753x_reg_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
|
|
- u32 set)
|
|
-{
|
|
- u32 val;
|
|
-
|
|
- mt753x_reg_read(priv, reg, &val);
|
|
- val &= ~clr;
|
|
- val |= set;
|
|
- mt753x_reg_write(priv, reg, val);
|
|
-}
|
|
-
|
|
-/* Indirect MDIO clause 22/45 access */
|
|
-static int mt7531_mii_rw(struct mtk_eth_priv *priv, int phy, int reg, u16 data,
|
|
- u32 cmd, u32 st)
|
|
-{
|
|
- ulong timeout;
|
|
- u32 val, timeout_ms;
|
|
- int ret = 0;
|
|
-
|
|
- val = (st << MDIO_ST_S) |
|
|
- ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
|
|
- ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
|
|
- ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
|
|
-
|
|
- if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
|
|
- val |= data & MDIO_RW_DATA_M;
|
|
-
|
|
- mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
|
|
-
|
|
- timeout_ms = 100;
|
|
- timeout = get_timer(0);
|
|
- while (1) {
|
|
- mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
|
|
-
|
|
- if ((val & PHY_ACS_ST) == 0)
|
|
- break;
|
|
-
|
|
- if (get_timer(timeout) > timeout_ms)
|
|
- return -ETIMEDOUT;
|
|
- }
|
|
-
|
|
- if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
|
|
- mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
|
|
- ret = val & MDIO_RW_DATA_M;
|
|
- }
|
|
-
|
|
- return ret;
|
|
-}
|
|
-
|
|
-static int mt7531_mii_ind_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
|
|
-{
|
|
- u8 phy_addr;
|
|
-
|
|
- if (phy >= MT753X_NUM_PHYS)
|
|
- return -EINVAL;
|
|
-
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy);
|
|
-
|
|
- return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
|
|
- MDIO_ST_C22);
|
|
-}
|
|
-
|
|
-static int mt7531_mii_ind_write(struct mtk_eth_priv *priv, u8 phy, u8 reg,
|
|
- u16 val)
|
|
-{
|
|
- u8 phy_addr;
|
|
-
|
|
- if (phy >= MT753X_NUM_PHYS)
|
|
- return -EINVAL;
|
|
-
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, phy);
|
|
-
|
|
- return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
|
|
- MDIO_ST_C22);
|
|
-}
|
|
-
|
|
-static int mt7531_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad,
|
|
- u16 reg)
|
|
-{
|
|
- u8 phy_addr;
|
|
- int ret;
|
|
-
|
|
- if (addr >= MT753X_NUM_PHYS)
|
|
- return -EINVAL;
|
|
-
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr);
|
|
-
|
|
- ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
|
|
- MDIO_ST_C45);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
|
|
- MDIO_ST_C45);
|
|
-}
|
|
-
|
|
-static int mt7531_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad,
|
|
- u16 reg, u16 val)
|
|
-{
|
|
- u8 phy_addr;
|
|
- int ret;
|
|
-
|
|
- if (addr >= MT753X_NUM_PHYS)
|
|
- return 0;
|
|
-
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, addr);
|
|
-
|
|
- ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
|
|
- MDIO_ST_C45);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
|
|
- MDIO_ST_C45);
|
|
-}
|
|
-
|
|
-static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
|
-{
|
|
- struct mtk_eth_priv *priv = bus->priv;
|
|
-
|
|
- if (devad < 0)
|
|
- return priv->mii_read(priv, addr, reg);
|
|
- else
|
|
- return priv->mmd_read(priv, addr, devad, reg);
|
|
-}
|
|
-
|
|
-static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
|
- u16 val)
|
|
-{
|
|
- struct mtk_eth_priv *priv = bus->priv;
|
|
-
|
|
- if (devad < 0)
|
|
- return priv->mii_write(priv, addr, reg, val);
|
|
- else
|
|
- return priv->mmd_write(priv, addr, devad, reg, val);
|
|
-}
|
|
-
|
|
-static int mtk_mdio_register(struct udevice *dev)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- struct mii_dev *mdio_bus = mdio_alloc();
|
|
- int ret;
|
|
-
|
|
- if (!mdio_bus)
|
|
- return -ENOMEM;
|
|
-
|
|
- /* Assign MDIO access APIs according to the switch/phy */
|
|
- switch (priv->sw) {
|
|
- case SW_MT7530:
|
|
- priv->mii_read = mtk_mii_read;
|
|
- priv->mii_write = mtk_mii_write;
|
|
- priv->mmd_read = mtk_mmd_ind_read;
|
|
- priv->mmd_write = mtk_mmd_ind_write;
|
|
- break;
|
|
- case SW_MT7531:
|
|
- case SW_MT7988:
|
|
- priv->mii_read = mt7531_mii_ind_read;
|
|
- priv->mii_write = mt7531_mii_ind_write;
|
|
- priv->mmd_read = mt7531_mmd_ind_read;
|
|
- priv->mmd_write = mt7531_mmd_ind_write;
|
|
- break;
|
|
- default:
|
|
- priv->mii_read = mtk_mii_read;
|
|
- priv->mii_write = mtk_mii_write;
|
|
- priv->mmd_read = mtk_mmd_read;
|
|
- priv->mmd_write = mtk_mmd_write;
|
|
- }
|
|
-
|
|
- mdio_bus->read = mtk_mdio_read;
|
|
- mdio_bus->write = mtk_mdio_write;
|
|
- snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
|
|
-
|
|
- mdio_bus->priv = (void *)priv;
|
|
-
|
|
- ret = mdio_register(mdio_bus);
|
|
-
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->mdio_bus = mdio_bus;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mt753x_core_reg_read(struct mtk_eth_priv *priv, u32 reg)
|
|
-{
|
|
- u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0);
|
|
-
|
|
- return priv->mmd_read(priv, phy_addr, 0x1f, reg);
|
|
-}
|
|
-
|
|
-static void mt753x_core_reg_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
|
|
-{
|
|
- u8 phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, 0);
|
|
-
|
|
- priv->mmd_write(priv, phy_addr, 0x1f, reg, val);
|
|
-}
|
|
-
|
|
-static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode)
|
|
-{
|
|
- u32 ncpo1, ssc_delta;
|
|
-
|
|
- switch (mode) {
|
|
- case PHY_INTERFACE_MODE_RGMII:
|
|
- ncpo1 = 0x0c80;
|
|
- ssc_delta = 0x87;
|
|
- break;
|
|
- default:
|
|
- printf("error: xMII mode %d not supported\n", mode);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /* Disable MT7530 core clock */
|
|
- mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
|
|
-
|
|
- /* Disable MT7530 PLL */
|
|
- mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1,
|
|
- (2 << RG_GSWPLL_POSDIV_200M_S) |
|
|
- (32 << RG_GSWPLL_FBKDIV_200M_S));
|
|
-
|
|
- /* For MT7530 core clock = 500Mhz */
|
|
- mt753x_core_reg_write(priv, CORE_GSWPLL_GRP2,
|
|
- (1 << RG_GSWPLL_POSDIV_500M_S) |
|
|
- (25 << RG_GSWPLL_FBKDIV_500M_S));
|
|
-
|
|
- /* Enable MT7530 PLL */
|
|
- mt753x_core_reg_write(priv, CORE_GSWPLL_GRP1,
|
|
- (2 << RG_GSWPLL_POSDIV_200M_S) |
|
|
- (32 << RG_GSWPLL_FBKDIV_200M_S) |
|
|
- RG_GSWPLL_EN_PRE);
|
|
-
|
|
- udelay(20);
|
|
-
|
|
- mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
|
|
-
|
|
- /* Setup the MT7530 TRGMII Tx Clock */
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP6, 0);
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
|
|
- RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
|
|
-
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP2,
|
|
- RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
|
|
- (1 << RG_SYSPLL_POSDIV_S));
|
|
-
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP7,
|
|
- RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
|
|
- RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
|
|
-
|
|
- /* Enable MT7530 core clock */
|
|
- mt753x_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
|
|
- REG_GSWCK_EN | REG_TRGMIICK_EN);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mt7530_mac_control(struct mtk_eth_priv *priv, bool enable)
|
|
-{
|
|
- u32 pmcr = FORCE_MODE;
|
|
-
|
|
- if (enable)
|
|
- pmcr = priv->mt753x_pmcr;
|
|
-
|
|
- mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
|
-}
|
|
-
|
|
-static int mt7530_setup(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u16 phy_addr, phy_val;
|
|
- u32 val, txdrv;
|
|
- int i;
|
|
-
|
|
- if (!MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
|
|
- /* Select 250MHz clk for RGMII mode */
|
|
- mtk_ethsys_rmw(priv, ETHSYS_CLKCFG0_REG,
|
|
- ETHSYS_TRGMII_CLK_SEL362_5, 0);
|
|
-
|
|
- txdrv = 8;
|
|
- } else {
|
|
- txdrv = 4;
|
|
- }
|
|
-
|
|
- /* Modify HWTRAP first to allow direct access to internal PHYs */
|
|
- mt753x_reg_read(priv, HWTRAP_REG, &val);
|
|
- val |= CHG_TRAP;
|
|
- val &= ~C_MDIO_BPS;
|
|
- mt753x_reg_write(priv, MHWTRAP_REG, val);
|
|
-
|
|
- /* Calculate the phy base address */
|
|
- val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
|
|
- priv->mt753x_phy_base = (val | 0x7) + 1;
|
|
-
|
|
- /* Turn off PHYs */
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
|
|
- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
|
|
- phy_val |= BMCR_PDOWN;
|
|
- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
- }
|
|
-
|
|
- /* Force MAC link down before reset */
|
|
- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
|
|
- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
|
|
-
|
|
- /* MT7530 reset */
|
|
- mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
|
|
- udelay(100);
|
|
-
|
|
- val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
- MAC_MODE | FORCE_MODE |
|
|
- MAC_TX_EN | MAC_RX_EN |
|
|
- BKOFF_EN | BACKPR_EN |
|
|
- (SPEED_1000M << FORCE_SPD_S) |
|
|
- FORCE_DPX | FORCE_LINK;
|
|
-
|
|
- /* MT7530 Port6: Forced 1000M/FD, FC disabled */
|
|
- priv->mt753x_pmcr = val;
|
|
-
|
|
- /* MT7530 Port5: Forced link down */
|
|
- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
|
|
-
|
|
- /* Keep MAC link down before starting eth */
|
|
- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
|
|
-
|
|
- /* MT7530 Port6: Set to RGMII */
|
|
- mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
|
|
-
|
|
- /* Hardware Trap: Enable Port6, Disable Port5 */
|
|
- mt753x_reg_read(priv, HWTRAP_REG, &val);
|
|
- val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
|
|
- (P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
|
|
- (P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
|
|
- val &= ~(C_MDIO_BPS | P6_INTF_DIS);
|
|
- mt753x_reg_write(priv, MHWTRAP_REG, val);
|
|
-
|
|
- /* Setup switch core pll */
|
|
- mt7530_pad_clk_setup(priv, priv->phy_interface);
|
|
-
|
|
- /* Lower Tx Driving for TRGMII path */
|
|
- for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
|
|
- mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
|
|
- (txdrv << TD_DM_DRVP_S) |
|
|
- (txdrv << TD_DM_DRVN_S));
|
|
-
|
|
- for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
|
|
- mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
|
|
-
|
|
- /* Turn on PHYs */
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
|
|
- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
|
|
- phy_val &= ~BMCR_PDOWN;
|
|
- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mt7531_core_pll_setup(struct mtk_eth_priv *priv, int mcm)
|
|
-{
|
|
- /* Step 1 : Disable MT7531 COREPLL */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
|
|
-
|
|
- /* Step 2: switch to XTAL output */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
|
|
-
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
|
|
-
|
|
- /* Step 3: disable PLLGP and enable program PLLGP */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
|
|
-
|
|
- /* Step 4: program COREPLL output frequency to 500MHz */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
|
|
- 2 << RG_COREPLL_POSDIV_S);
|
|
- udelay(25);
|
|
-
|
|
- /* Currently, support XTAL 25Mhz only */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
|
|
- 0x140000 << RG_COREPLL_SDM_PCW_S);
|
|
-
|
|
- /* Set feedback divide ratio update signal to high */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
|
|
- RG_COREPLL_SDM_PCW_CHG);
|
|
-
|
|
- /* Wait for at least 16 XTAL clocks */
|
|
- udelay(10);
|
|
-
|
|
- /* Step 5: set feedback divide ratio update signal to low */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
|
|
-
|
|
- /* add enable 325M clock for SGMII */
|
|
- mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
|
|
-
|
|
- /* add enable 250SSC clock for RGMII */
|
|
- mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
|
|
-
|
|
- /*Step 6: Enable MT7531 PLL */
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
|
|
-
|
|
- mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
|
|
-
|
|
- udelay(25);
|
|
-}
|
|
-
|
|
-static int mt7531_port_sgmii_init(struct mtk_eth_priv *priv,
|
|
- u32 port)
|
|
-{
|
|
- if (port != 5 && port != 6) {
|
|
- printf("mt7531: port %d is not a SGMII port\n", port);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /* Set SGMII GEN2 speed(2.5G) */
|
|
- mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
|
|
- FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
|
|
-
|
|
- /* Disable SGMII AN */
|
|
- mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
|
|
- SGMII_AN_ENABLE, 0);
|
|
-
|
|
- /* SGMII force mode setting */
|
|
- mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
|
|
-
|
|
- /* Release PHYA power down state */
|
|
- mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
|
|
- SGMII_PHYA_PWD, 0);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mt7531_port_rgmii_init(struct mtk_eth_priv *priv, u32 port)
|
|
-{
|
|
- u32 val;
|
|
-
|
|
- if (port != 5) {
|
|
- printf("error: RGMII mode is not available for port %d\n",
|
|
- port);
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
|
|
- val |= GP_CLK_EN;
|
|
- val &= ~GP_MODE_M;
|
|
- val |= GP_MODE_RGMII << GP_MODE_S;
|
|
- val |= TXCLK_NO_REVERSE;
|
|
- val |= RXCLK_NO_DELAY;
|
|
- val &= ~CLK_SKEW_IN_M;
|
|
- val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
|
|
- val &= ~CLK_SKEW_OUT_M;
|
|
- val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
|
|
- mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mt7531_phy_setting(struct mtk_eth_priv *priv)
|
|
-{
|
|
- int i;
|
|
- u32 val;
|
|
-
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- /* Enable HW auto downshift */
|
|
- priv->mii_write(priv, i, 0x1f, 0x1);
|
|
- val = priv->mii_read(priv, i, PHY_EXT_REG_14);
|
|
- val |= PHY_EN_DOWN_SHFIT;
|
|
- priv->mii_write(priv, i, PHY_EXT_REG_14, val);
|
|
-
|
|
- /* PHY link down power saving enable */
|
|
- val = priv->mii_read(priv, i, PHY_EXT_REG_17);
|
|
- val |= PHY_LINKDOWN_POWER_SAVING_EN;
|
|
- priv->mii_write(priv, i, PHY_EXT_REG_17, val);
|
|
-
|
|
- val = priv->mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
|
|
- val &= ~PHY_POWER_SAVING_M;
|
|
- val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
|
|
- priv->mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
|
|
- }
|
|
-}
|
|
-
|
|
-static void mt7531_mac_control(struct mtk_eth_priv *priv, bool enable)
|
|
-{
|
|
- u32 pmcr = FORCE_MODE_LNK;
|
|
-
|
|
- if (enable)
|
|
- pmcr = priv->mt753x_pmcr;
|
|
-
|
|
- mt753x_reg_write(priv, PMCR_REG(5), pmcr);
|
|
- mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
|
-}
|
|
-
|
|
-static int mt7531_setup(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u16 phy_addr, phy_val;
|
|
- u32 val;
|
|
- u32 pmcr;
|
|
- u32 port5_sgmii;
|
|
- int i;
|
|
-
|
|
- priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
|
|
- MT753X_SMI_ADDR_MASK;
|
|
-
|
|
- /* Turn off PHYs */
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
|
|
- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
|
|
- phy_val |= BMCR_PDOWN;
|
|
- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
- }
|
|
-
|
|
- /* Force MAC link down before reset */
|
|
- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
|
|
- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
|
-
|
|
- /* Switch soft reset */
|
|
- mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
|
|
- udelay(100);
|
|
-
|
|
- /* Enable MDC input Schmitt Trigger */
|
|
- mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
|
|
- SMT_IOLB_5_SMI_MDC_EN);
|
|
-
|
|
- mt7531_core_pll_setup(priv, priv->mcm);
|
|
-
|
|
- mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
|
|
- port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
|
|
-
|
|
- /* port5 support either RGMII or SGMII, port6 only support SGMII. */
|
|
- switch (priv->phy_interface) {
|
|
- case PHY_INTERFACE_MODE_RGMII:
|
|
- if (!port5_sgmii)
|
|
- mt7531_port_rgmii_init(priv, 5);
|
|
- break;
|
|
- case PHY_INTERFACE_MODE_2500BASEX:
|
|
- mt7531_port_sgmii_init(priv, 6);
|
|
- if (port5_sgmii)
|
|
- mt7531_port_sgmii_init(priv, 5);
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
-
|
|
- pmcr = MT7531_FORCE_MODE |
|
|
- (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
- MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
|
- BKOFF_EN | BACKPR_EN |
|
|
- FORCE_RX_FC | FORCE_TX_FC |
|
|
- (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
|
|
- FORCE_LINK;
|
|
-
|
|
- priv->mt753x_pmcr = pmcr;
|
|
-
|
|
- /* Keep MAC link down before starting eth */
|
|
- mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
|
|
- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
|
-
|
|
- /* Turn on PHYs */
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
|
|
- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
|
|
- phy_val &= ~BMCR_PDOWN;
|
|
- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
- }
|
|
-
|
|
- mt7531_phy_setting(priv);
|
|
-
|
|
- /* Enable Internal PHYs */
|
|
- val = mt753x_core_reg_read(priv, CORE_PLL_GROUP4);
|
|
- val |= MT7531_BYPASS_MODE;
|
|
- val &= ~MT7531_POWER_ON_OFF;
|
|
- mt753x_core_reg_write(priv, CORE_PLL_GROUP4, val);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mt7988_phy_setting(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u16 val;
|
|
- u32 i;
|
|
-
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- /* Enable HW auto downshift */
|
|
- priv->mii_write(priv, i, 0x1f, 0x1);
|
|
- val = priv->mii_read(priv, i, PHY_EXT_REG_14);
|
|
- val |= PHY_EN_DOWN_SHFIT;
|
|
- priv->mii_write(priv, i, PHY_EXT_REG_14, val);
|
|
-
|
|
- /* PHY link down power saving enable */
|
|
- val = priv->mii_read(priv, i, PHY_EXT_REG_17);
|
|
- val |= PHY_LINKDOWN_POWER_SAVING_EN;
|
|
- priv->mii_write(priv, i, PHY_EXT_REG_17, val);
|
|
- }
|
|
-}
|
|
-
|
|
-static void mt7988_mac_control(struct mtk_eth_priv *priv, bool enable)
|
|
-{
|
|
- u32 pmcr = FORCE_MODE_LNK;
|
|
-
|
|
- if (enable)
|
|
- pmcr = priv->mt753x_pmcr;
|
|
-
|
|
- mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
|
-}
|
|
-
|
|
-static int mt7988_setup(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u16 phy_addr, phy_val;
|
|
- u32 pmcr;
|
|
- int i;
|
|
-
|
|
- priv->gsw_base = regmap_get_range(priv->ethsys_regmap, 0) + GSW_BASE;
|
|
-
|
|
- priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
|
|
- MT753X_SMI_ADDR_MASK;
|
|
-
|
|
- /* Turn off PHYs */
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
|
|
- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
|
|
- phy_val |= BMCR_PDOWN;
|
|
- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
- }
|
|
-
|
|
- switch (priv->phy_interface) {
|
|
- case PHY_INTERFACE_MODE_USXGMII:
|
|
- /* Use CPU bridge instead of actual USXGMII path */
|
|
-
|
|
- /* Set GDM1 no drop */
|
|
- mtk_fe_rmw(priv, PSE_NO_DROP_CFG_REG, 0, PSE_NO_DROP_GDM1);
|
|
-
|
|
- /* Enable GDM1 to GSW CPU bridge */
|
|
- mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, BIT(0));
|
|
-
|
|
- /* XGMAC force link up */
|
|
- mtk_gmac_rmw(priv, GMAC_XGMAC_STS_REG, 0, P1_XGMAC_FORCE_LINK);
|
|
-
|
|
- /* Setup GSW CPU bridge IPG */
|
|
- mtk_gmac_rmw(priv, GMAC_GSW_CFG_REG, GSWTX_IPG_M | GSWRX_IPG_M,
|
|
- (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
|
|
- break;
|
|
- default:
|
|
- printf("Error: MT7988 GSW does not support %s interface\n",
|
|
- phy_string_for_interface(priv->phy_interface));
|
|
- break;
|
|
- }
|
|
-
|
|
- pmcr = MT7988_FORCE_MODE |
|
|
- (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
- MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
|
- BKOFF_EN | BACKPR_EN |
|
|
- FORCE_RX_FC | FORCE_TX_FC |
|
|
- (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
|
|
- FORCE_LINK;
|
|
-
|
|
- priv->mt753x_pmcr = pmcr;
|
|
-
|
|
- /* Keep MAC link down before starting eth */
|
|
- mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
|
-
|
|
- /* Turn on PHYs */
|
|
- for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
|
- phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
|
|
- phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
|
|
- phy_val &= ~BMCR_PDOWN;
|
|
- priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
|
- }
|
|
-
|
|
- mt7988_phy_setting(priv);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mt753x_switch_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- int ret;
|
|
- int i;
|
|
-
|
|
- /* Global reset switch */
|
|
- if (priv->mcm) {
|
|
- reset_assert(&priv->rst_mcm);
|
|
- udelay(1000);
|
|
- reset_deassert(&priv->rst_mcm);
|
|
- mdelay(priv->mt753x_reset_wait_time);
|
|
- } else if (dm_gpio_is_valid(&priv->rst_gpio)) {
|
|
- dm_gpio_set_value(&priv->rst_gpio, 0);
|
|
- udelay(1000);
|
|
- dm_gpio_set_value(&priv->rst_gpio, 1);
|
|
- mdelay(priv->mt753x_reset_wait_time);
|
|
- }
|
|
-
|
|
- ret = priv->switch_init(priv);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Set port isolation */
|
|
- for (i = 0; i < MT753X_NUM_PORTS; i++) {
|
|
- /* Set port matrix mode */
|
|
- if (i != 6)
|
|
- mt753x_reg_write(priv, PCR_REG(i),
|
|
- (0x40 << PORT_MATRIX_S));
|
|
- else
|
|
- mt753x_reg_write(priv, PCR_REG(i),
|
|
- (0x3f << PORT_MATRIX_S));
|
|
-
|
|
- /* Set port mode to user port */
|
|
- mt753x_reg_write(priv, PVC_REG(i),
|
|
- (0x8100 << STAG_VPID_S) |
|
|
- (VLAN_ATTR_USER << VLAN_ATTR_S));
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u16 lcl_adv = 0, rmt_adv = 0;
|
|
- u8 flowctrl;
|
|
- u32 mcr;
|
|
-
|
|
- mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id));
|
|
- mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC);
|
|
-
|
|
- if (priv->phydev->duplex) {
|
|
- if (priv->phydev->pause)
|
|
- rmt_adv = LPA_PAUSE_CAP;
|
|
- if (priv->phydev->asym_pause)
|
|
- rmt_adv |= LPA_PAUSE_ASYM;
|
|
-
|
|
- if (priv->phydev->advertising & ADVERTISED_Pause)
|
|
- lcl_adv |= ADVERTISE_PAUSE_CAP;
|
|
- if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
|
|
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
|
|
-
|
|
- flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
|
|
-
|
|
- if (flowctrl & FLOW_CTRL_TX)
|
|
- mcr |= XGMAC_FORCE_TX_FC;
|
|
- if (flowctrl & FLOW_CTRL_RX)
|
|
- mcr |= XGMAC_FORCE_RX_FC;
|
|
-
|
|
- debug("rx pause %s, tx pause %s\n",
|
|
- flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
|
|
- flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
|
|
- }
|
|
-
|
|
- mcr &= ~(XGMAC_TRX_DISABLE);
|
|
- mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr);
|
|
-}
|
|
-
|
|
-static void mtk_phy_link_adjust(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u16 lcl_adv = 0, rmt_adv = 0;
|
|
- u8 flowctrl;
|
|
- u32 mcr;
|
|
-
|
|
- mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
- (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
|
|
- MAC_MODE | FORCE_MODE |
|
|
- MAC_TX_EN | MAC_RX_EN |
|
|
- DEL_RXFIFO_CLR |
|
|
- BKOFF_EN | BACKPR_EN;
|
|
-
|
|
- switch (priv->phydev->speed) {
|
|
- case SPEED_10:
|
|
- mcr |= (SPEED_10M << FORCE_SPD_S);
|
|
- break;
|
|
- case SPEED_100:
|
|
- mcr |= (SPEED_100M << FORCE_SPD_S);
|
|
- break;
|
|
- case SPEED_1000:
|
|
- case SPEED_2500:
|
|
- mcr |= (SPEED_1000M << FORCE_SPD_S);
|
|
- break;
|
|
- };
|
|
-
|
|
- if (priv->phydev->link)
|
|
- mcr |= FORCE_LINK;
|
|
-
|
|
- if (priv->phydev->duplex) {
|
|
- mcr |= FORCE_DPX;
|
|
-
|
|
- if (priv->phydev->pause)
|
|
- rmt_adv = LPA_PAUSE_CAP;
|
|
- if (priv->phydev->asym_pause)
|
|
- rmt_adv |= LPA_PAUSE_ASYM;
|
|
-
|
|
- if (priv->phydev->advertising & ADVERTISED_Pause)
|
|
- lcl_adv |= ADVERTISE_PAUSE_CAP;
|
|
- if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
|
|
- lcl_adv |= ADVERTISE_PAUSE_ASYM;
|
|
-
|
|
- flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
|
|
-
|
|
- if (flowctrl & FLOW_CTRL_TX)
|
|
- mcr |= FORCE_TX_FC;
|
|
- if (flowctrl & FLOW_CTRL_RX)
|
|
- mcr |= FORCE_RX_FC;
|
|
-
|
|
- debug("rx pause %s, tx pause %s\n",
|
|
- flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
|
|
- flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
|
|
- }
|
|
-
|
|
- mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
|
|
-}
|
|
-
|
|
-static int mtk_phy_start(struct mtk_eth_priv *priv)
|
|
-{
|
|
- struct phy_device *phydev = priv->phydev;
|
|
- int ret;
|
|
-
|
|
- ret = phy_startup(phydev);
|
|
-
|
|
- if (ret) {
|
|
- debug("Could not initialize PHY %s\n", phydev->dev->name);
|
|
- return ret;
|
|
- }
|
|
-
|
|
- if (!phydev->link) {
|
|
- debug("%s: link down.\n", phydev->dev->name);
|
|
- return 0;
|
|
- }
|
|
-
|
|
- if (!priv->force_mode) {
|
|
- if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
|
|
- mtk_xphy_link_adjust(priv);
|
|
- else
|
|
- mtk_phy_link_adjust(priv);
|
|
- }
|
|
-
|
|
- debug("Speed: %d, %s duplex%s\n", phydev->speed,
|
|
- (phydev->duplex) ? "full" : "half",
|
|
- (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mtk_phy_probe(struct udevice *dev)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- struct phy_device *phydev;
|
|
-
|
|
- phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev,
|
|
- priv->phy_interface);
|
|
- if (!phydev)
|
|
- return -ENODEV;
|
|
-
|
|
- phydev->supported &= PHY_GBIT_FEATURES;
|
|
- phydev->advertising = phydev->supported;
|
|
-
|
|
- priv->phydev = phydev;
|
|
- phy_config(phydev);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- /* Set SGMII GEN1 speed(1G) */
|
|
- clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
|
|
-
|
|
- /* Enable SGMII AN */
|
|
- setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
|
|
- SGMII_AN_ENABLE);
|
|
-
|
|
- /* SGMII AN mode setting */
|
|
- writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
|
|
-
|
|
- /* SGMII PN SWAP setting */
|
|
- if (priv->pn_swap) {
|
|
- setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
|
|
- SGMII_PN_SWAP_TX_RX);
|
|
- }
|
|
-
|
|
- /* Release PHYA power down state */
|
|
- clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
|
|
- SGMII_PHYA_PWD, 0);
|
|
-}
|
|
-
|
|
-static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- /* Set SGMII GEN2 speed(2.5G) */
|
|
- clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
|
|
- SGMSYS_SPEED_MASK,
|
|
- FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
|
|
-
|
|
- /* Disable SGMII AN */
|
|
- clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
|
|
- SGMII_AN_ENABLE, 0);
|
|
-
|
|
- /* SGMII force mode setting */
|
|
- writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
|
|
-
|
|
- /* SGMII PN SWAP setting */
|
|
- if (priv->pn_swap) {
|
|
- setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
|
|
- SGMII_PN_SWAP_TX_RX);
|
|
- }
|
|
-
|
|
- /* Release PHYA power down state */
|
|
- clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
|
|
- SGMII_PHYA_PWD, 0);
|
|
-}
|
|
-
|
|
-static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u32 val = 0;
|
|
-
|
|
- /* Add software workaround for USXGMII PLL TCL issue */
|
|
- regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8,
|
|
- RG_XFI_PLL_ANA_SWWA);
|
|
-
|
|
- regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val);
|
|
- val |= RG_XFI_PLL_EN;
|
|
- regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val);
|
|
-}
|
|
-
|
|
-static void mtk_usxgmii_reset(struct mtk_eth_priv *priv)
|
|
-{
|
|
- switch (priv->gmac_id) {
|
|
- case 1:
|
|
- regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004);
|
|
- regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004);
|
|
- regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
|
|
- regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
|
|
- regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
|
|
- break;
|
|
- case 2:
|
|
- regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002);
|
|
- regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002);
|
|
- regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
|
|
- regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
|
|
- regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
|
|
- break;
|
|
- }
|
|
-
|
|
- mdelay(10);
|
|
-}
|
|
-
|
|
-static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv)
|
|
-{
|
|
- regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D);
|
|
- regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
|
|
- regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000);
|
|
-
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
|
|
- udelay(150);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
|
|
- udelay(15);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
|
|
- udelay(100);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
|
|
- udelay(400);
|
|
-}
|
|
-
|
|
-static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
|
|
-{
|
|
- regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
|
|
- regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
|
|
- regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
|
|
- ndelay(1020);
|
|
-
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
|
|
- if (priv->gmac_id == 2)
|
|
- regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
|
|
- udelay(150);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
|
|
- udelay(15);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
|
|
- ndelay(1020);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
|
|
- udelay(100);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
|
|
- regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
|
|
- udelay(400);
|
|
-}
|
|
-
|
|
-static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- mtk_xfi_pll_enable(priv);
|
|
- mtk_usxgmii_reset(priv);
|
|
- mtk_usxgmii_setup_phya_an_10000(priv);
|
|
-}
|
|
-
|
|
-static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- mtk_xfi_pll_enable(priv);
|
|
- mtk_usxgmii_reset(priv);
|
|
- mtk_usxgmii_setup_phya_force_10000(priv);
|
|
-}
|
|
-
|
|
-static int mtk_mac_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- int i, sgmii_sel_mask = 0, ge_mode = 0;
|
|
- u32 mcr;
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
|
|
- mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
|
|
- INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
|
|
- }
|
|
-
|
|
- switch (priv->phy_interface) {
|
|
- case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
- case PHY_INTERFACE_MODE_RGMII:
|
|
- ge_mode = GE_MODE_RGMII;
|
|
- break;
|
|
- case PHY_INTERFACE_MODE_SGMII:
|
|
- case PHY_INTERFACE_MODE_2500BASEX:
|
|
- if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
|
|
- printf("Error: SGMII is not supported on this platform\n");
|
|
- return -ENOTSUPP;
|
|
- }
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
|
|
- mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
|
|
- SGMII_QPHY_SEL);
|
|
- }
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
|
|
- sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
|
|
-
|
|
- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
|
|
- SYSCFG1_SGMII_SEL(priv->gmac_id));
|
|
-
|
|
- if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
|
|
- mtk_sgmii_an_init(priv);
|
|
- else
|
|
- mtk_sgmii_force_init(priv);
|
|
-
|
|
- ge_mode = GE_MODE_RGMII;
|
|
- break;
|
|
- case PHY_INTERFACE_MODE_MII:
|
|
- case PHY_INTERFACE_MODE_GMII:
|
|
- ge_mode = GE_MODE_MII;
|
|
- break;
|
|
- case PHY_INTERFACE_MODE_RMII:
|
|
- ge_mode = GE_MODE_RMII;
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
-
|
|
- /* set the gmac to the right mode */
|
|
- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
|
|
- SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
|
|
- ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
|
|
-
|
|
- if (priv->force_mode) {
|
|
- mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
- (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
|
|
- MAC_MODE | FORCE_MODE |
|
|
- MAC_TX_EN | MAC_RX_EN |
|
|
- BKOFF_EN | BACKPR_EN |
|
|
- FORCE_LINK;
|
|
-
|
|
- switch (priv->speed) {
|
|
- case SPEED_10:
|
|
- mcr |= SPEED_10M << FORCE_SPD_S;
|
|
- break;
|
|
- case SPEED_100:
|
|
- mcr |= SPEED_100M << FORCE_SPD_S;
|
|
- break;
|
|
- case SPEED_1000:
|
|
- case SPEED_2500:
|
|
- mcr |= SPEED_1000M << FORCE_SPD_S;
|
|
- break;
|
|
- }
|
|
-
|
|
- if (priv->duplex)
|
|
- mcr |= FORCE_DPX;
|
|
-
|
|
- mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
|
|
- }
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
|
|
- !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
|
|
- /* Lower Tx Driving for TRGMII path */
|
|
- for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
|
|
- mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
|
|
- (8 << TD_DM_DRVP_S) |
|
|
- (8 << TD_DM_DRVN_S));
|
|
-
|
|
- mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0,
|
|
- RX_RST | RXC_DQSISEL);
|
|
- mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mtk_xmac_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u32 force_link = 0;
|
|
-
|
|
- if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
|
|
- printf("Error: 10Gb interface is not supported on this platform\n");
|
|
- return -ENOTSUPP;
|
|
- }
|
|
-
|
|
- switch (priv->phy_interface) {
|
|
- case PHY_INTERFACE_MODE_USXGMII:
|
|
- mtk_usxgmii_an_init(priv);
|
|
- break;
|
|
- case PHY_INTERFACE_MODE_10GBASER:
|
|
- mtk_10gbaser_init(priv);
|
|
- break;
|
|
- default:
|
|
- break;
|
|
- }
|
|
-
|
|
- /* Set GMAC to the correct mode */
|
|
- mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
|
|
- SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
|
|
- 0);
|
|
-
|
|
- if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
|
|
- priv->gmac_id == 1) {
|
|
- mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
|
|
- NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
|
|
- }
|
|
-
|
|
- if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII ||
|
|
- priv->gmac_id == 2)
|
|
- force_link = XGMAC_FORCE_LINK(priv->gmac_id);
|
|
-
|
|
- mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id),
|
|
- XGMAC_FORCE_LINK(priv->gmac_id), force_link);
|
|
-
|
|
- /* Force GMAC link down */
|
|
- mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- char *pkt_base = priv->pkt_pool;
|
|
- struct mtk_tx_dma_v2 *txd;
|
|
- struct mtk_rx_dma_v2 *rxd;
|
|
- int i;
|
|
-
|
|
- mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
|
|
- udelay(500);
|
|
-
|
|
- memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
|
|
- memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
|
|
- memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
|
|
-
|
|
- flush_dcache_range((ulong)pkt_base,
|
|
- (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
|
|
-
|
|
- priv->rx_dma_owner_idx0 = 0;
|
|
- priv->tx_cpu_owner_idx0 = 0;
|
|
-
|
|
- for (i = 0; i < NUM_TX_DESC; i++) {
|
|
- txd = priv->tx_ring_noc + i * priv->soc->txd_size;
|
|
-
|
|
- txd->txd1 = virt_to_phys(pkt_base);
|
|
- txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ?
|
|
- 15 : priv->gmac_id + 1);
|
|
- else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
|
|
- txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
|
|
- else
|
|
- txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
|
|
-
|
|
- pkt_base += PKTSIZE_ALIGN;
|
|
- }
|
|
-
|
|
- for (i = 0; i < NUM_RX_DESC; i++) {
|
|
- rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
|
|
-
|
|
- rxd->rxd1 = virt_to_phys(pkt_base);
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
- else
|
|
- rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
-
|
|
- pkt_base += PKTSIZE_ALIGN;
|
|
- }
|
|
-
|
|
- mtk_pdma_write(priv, TX_BASE_PTR_REG(0),
|
|
- virt_to_phys(priv->tx_ring_noc));
|
|
- mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC);
|
|
- mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
|
|
-
|
|
- mtk_pdma_write(priv, RX_BASE_PTR_REG(0),
|
|
- virt_to_phys(priv->rx_ring_noc));
|
|
- mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC);
|
|
- mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1);
|
|
-
|
|
- mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0);
|
|
-}
|
|
-
|
|
-static void mtk_eth_mdc_init(struct mtk_eth_priv *priv)
|
|
-{
|
|
- u32 divider;
|
|
-
|
|
- if (priv->mdc == 0)
|
|
- return;
|
|
-
|
|
- divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER);
|
|
-
|
|
- /* Configure MDC turbo mode */
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO);
|
|
- else
|
|
- mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO);
|
|
-
|
|
- /* Configure MDC divider */
|
|
- mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG,
|
|
- FIELD_PREP(PHY_MDC_CFG, divider));
|
|
-}
|
|
-
|
|
-static int mtk_eth_start(struct udevice *dev)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- int i, ret;
|
|
-
|
|
- /* Reset FE */
|
|
- reset_assert(&priv->rst_fe);
|
|
- udelay(1000);
|
|
- reset_deassert(&priv->rst_fe);
|
|
- mdelay(10);
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
|
|
-
|
|
- /* Packets forward to PDMA */
|
|
- mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
|
|
-
|
|
- for (i = 0; i < priv->soc->gdma_count; i++) {
|
|
- if (i == priv->gmac_id)
|
|
- continue;
|
|
-
|
|
- mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD);
|
|
- }
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) {
|
|
- if (priv->sw == SW_MT7988 && priv->gmac_id == 0) {
|
|
- mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
|
|
- GDMA_BRIDGE_TO_CPU);
|
|
-
|
|
- mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
|
|
- GDMA_CPU_BRIDGE_EN);
|
|
- } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
|
|
- priv->gmac_id != 0) {
|
|
- mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
|
|
- GDMA_CPU_BRIDGE_EN);
|
|
- }
|
|
- }
|
|
-
|
|
- udelay(500);
|
|
-
|
|
- mtk_eth_fifo_init(priv);
|
|
-
|
|
- if (priv->switch_mac_control)
|
|
- priv->switch_mac_control(priv, true);
|
|
-
|
|
- /* Start PHY */
|
|
- if (priv->sw == SW_NONE) {
|
|
- ret = mtk_phy_start(priv);
|
|
- if (ret)
|
|
- return ret;
|
|
- }
|
|
-
|
|
- mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0,
|
|
- TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
|
|
- udelay(500);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static void mtk_eth_stop(struct udevice *dev)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
-
|
|
- if (priv->switch_mac_control)
|
|
- priv->switch_mac_control(priv, false);
|
|
-
|
|
- mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG,
|
|
- TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
|
|
- udelay(500);
|
|
-
|
|
- wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
|
|
- RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
|
|
-}
|
|
-
|
|
-static int mtk_eth_write_hwaddr(struct udevice *dev)
|
|
-{
|
|
- struct eth_pdata *pdata = dev_get_plat(dev);
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- unsigned char *mac = pdata->enetaddr;
|
|
- u32 macaddr_lsb, macaddr_msb;
|
|
-
|
|
- macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1];
|
|
- macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) |
|
|
- ((u32)mac[4] << 8) | (u32)mac[5];
|
|
-
|
|
- mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb);
|
|
- mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mtk_eth_send(struct udevice *dev, void *packet, int length)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- u32 idx = priv->tx_cpu_owner_idx0;
|
|
- struct mtk_tx_dma_v2 *txd;
|
|
- void *pkt_base;
|
|
-
|
|
- txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
|
|
-
|
|
- if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
|
|
- debug("mtk-eth: TX DMA descriptor ring is full\n");
|
|
- return -EPERM;
|
|
- }
|
|
-
|
|
- pkt_base = (void *)phys_to_virt(txd->txd1);
|
|
- memcpy(pkt_base, packet, length);
|
|
- flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
|
|
- roundup(length, ARCH_DMA_MINALIGN));
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
|
|
- else
|
|
- txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
|
|
-
|
|
- priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
|
|
- mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- u32 idx = priv->rx_dma_owner_idx0;
|
|
- struct mtk_rx_dma_v2 *rxd;
|
|
- uchar *pkt_base;
|
|
- u32 length;
|
|
-
|
|
- rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
|
|
-
|
|
- if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
|
|
- debug("mtk-eth: RX DMA descriptor ring is empty\n");
|
|
- return -EAGAIN;
|
|
- }
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
|
|
- else
|
|
- length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
|
|
-
|
|
- pkt_base = (void *)phys_to_virt(rxd->rxd1);
|
|
- invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
|
|
- roundup(length, ARCH_DMA_MINALIGN));
|
|
-
|
|
- if (packetp)
|
|
- *packetp = pkt_base;
|
|
-
|
|
- return length;
|
|
-}
|
|
-
|
|
-static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- u32 idx = priv->rx_dma_owner_idx0;
|
|
- struct mtk_rx_dma_v2 *rxd;
|
|
-
|
|
- rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
|
|
-
|
|
- invalidate_dcache_range((ulong)rxd->rxd1,
|
|
- (ulong)rxd->rxd1 + PKTSIZE_ALIGN);
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
- MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
- rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
- else
|
|
- rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
-
|
|
- mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
|
|
- priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mtk_eth_probe(struct udevice *dev)
|
|
-{
|
|
- struct eth_pdata *pdata = dev_get_plat(dev);
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- ulong iobase = pdata->iobase;
|
|
- int ret;
|
|
-
|
|
- /* Frame Engine Register Base */
|
|
- priv->fe_base = (void *)iobase;
|
|
-
|
|
- /* GMAC Register Base */
|
|
- priv->gmac_base = (void *)(iobase + GMAC_BASE);
|
|
-
|
|
- /* MDIO register */
|
|
- ret = mtk_mdio_register(dev);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Prepare for tx/rx rings */
|
|
- priv->tx_ring_noc = (void *)
|
|
- noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
|
|
- ARCH_DMA_MINALIGN);
|
|
- priv->rx_ring_noc = (void *)
|
|
- noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
|
|
- ARCH_DMA_MINALIGN);
|
|
-
|
|
- /* Set MDC divider */
|
|
- mtk_eth_mdc_init(priv);
|
|
-
|
|
- /* Set MAC mode */
|
|
- if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
|
|
- ret = mtk_xmac_init(priv);
|
|
- else
|
|
- ret = mtk_mac_init(priv);
|
|
-
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- /* Probe phy if switch is not specified */
|
|
- if (priv->sw == SW_NONE)
|
|
- return mtk_phy_probe(dev);
|
|
-
|
|
- /* Initialize switch */
|
|
- return mt753x_switch_init(priv);
|
|
-}
|
|
-
|
|
-static int mtk_eth_remove(struct udevice *dev)
|
|
-{
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
-
|
|
- /* MDIO unregister */
|
|
- mdio_unregister(priv->mdio_bus);
|
|
- mdio_free(priv->mdio_bus);
|
|
-
|
|
- /* Stop possibly started DMA */
|
|
- mtk_eth_stop(dev);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static int mtk_eth_of_to_plat(struct udevice *dev)
|
|
-{
|
|
- struct eth_pdata *pdata = dev_get_plat(dev);
|
|
- struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
- struct ofnode_phandle_args args;
|
|
- struct regmap *regmap;
|
|
- const char *str;
|
|
- ofnode subnode;
|
|
- int ret;
|
|
-
|
|
- priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
|
|
- if (!priv->soc) {
|
|
- dev_err(dev, "missing soc compatible data\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
|
|
-
|
|
- /* get corresponding ethsys phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
|
|
- &args);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->ethsys_regmap = syscon_node_to_regmap(args.node);
|
|
- if (IS_ERR(priv->ethsys_regmap))
|
|
- return PTR_ERR(priv->ethsys_regmap);
|
|
-
|
|
- if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) {
|
|
- /* get corresponding infracfg phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,infracfg",
|
|
- NULL, 0, 0, &args);
|
|
-
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->infra_regmap = syscon_node_to_regmap(args.node);
|
|
- if (IS_ERR(priv->infra_regmap))
|
|
- return PTR_ERR(priv->infra_regmap);
|
|
- }
|
|
-
|
|
- /* Reset controllers */
|
|
- ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
|
|
- if (ret) {
|
|
- printf("error: Unable to get reset ctrl for frame engine\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
- priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0);
|
|
-
|
|
- priv->mdc = 0;
|
|
- subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio");
|
|
- if (ofnode_valid(subnode)) {
|
|
- priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000);
|
|
- if (priv->mdc > MDC_MAX_FREQ ||
|
|
- priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
|
|
- printf("error: MDIO clock frequency out of range\n");
|
|
- return -EINVAL;
|
|
- }
|
|
- }
|
|
-
|
|
- /* Interface mode is required */
|
|
- pdata->phy_interface = dev_read_phy_mode(dev);
|
|
- priv->phy_interface = pdata->phy_interface;
|
|
- if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
|
|
- printf("error: phy-mode is not set\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- /* Force mode or autoneg */
|
|
- subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link");
|
|
- if (ofnode_valid(subnode)) {
|
|
- priv->force_mode = 1;
|
|
- priv->speed = ofnode_read_u32_default(subnode, "speed", 0);
|
|
- priv->duplex = ofnode_read_bool(subnode, "full-duplex");
|
|
-
|
|
- if (priv->speed != SPEED_10 && priv->speed != SPEED_100 &&
|
|
- priv->speed != SPEED_1000 && priv->speed != SPEED_2500 &&
|
|
- priv->speed != SPEED_10000) {
|
|
- printf("error: no valid speed set in fixed-link\n");
|
|
- return -EINVAL;
|
|
- }
|
|
- }
|
|
-
|
|
- if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
|
|
- IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
|
|
- /* get corresponding sgmii phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
|
|
- NULL, 0, 0, &args);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- regmap = syscon_node_to_regmap(args.node);
|
|
-
|
|
- if (IS_ERR(regmap))
|
|
- return PTR_ERR(regmap);
|
|
-
|
|
- priv->sgmii_base = regmap_get_range(regmap, 0);
|
|
-
|
|
- if (!priv->sgmii_base) {
|
|
- dev_err(dev, "Unable to find sgmii\n");
|
|
- return -ENODEV;
|
|
- }
|
|
-
|
|
- /* Upstream linux use mediatek,pnswap instead of pn_swap */
|
|
- priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
|
|
- ofnode_read_bool(args.node, "mediatek,pnswap");
|
|
- } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
- priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
|
|
- IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
|
|
- /* get corresponding usxgmii phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
|
|
- NULL, 0, 0, &args);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->usxgmii_regmap = syscon_node_to_regmap(args.node);
|
|
- if (IS_ERR(priv->usxgmii_regmap))
|
|
- return PTR_ERR(priv->usxgmii_regmap);
|
|
-
|
|
- /* get corresponding xfi_pextp phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp",
|
|
- NULL, 0, 0, &args);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node);
|
|
- if (IS_ERR(priv->xfi_pextp_regmap))
|
|
- return PTR_ERR(priv->xfi_pextp_regmap);
|
|
-
|
|
- /* get corresponding xfi_pll phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll",
|
|
- NULL, 0, 0, &args);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->xfi_pll_regmap = syscon_node_to_regmap(args.node);
|
|
- if (IS_ERR(priv->xfi_pll_regmap))
|
|
- return PTR_ERR(priv->xfi_pll_regmap);
|
|
-
|
|
- /* get corresponding toprgu phandle */
|
|
- ret = dev_read_phandle_with_args(dev, "mediatek,toprgu",
|
|
- NULL, 0, 0, &args);
|
|
- if (ret)
|
|
- return ret;
|
|
-
|
|
- priv->toprgu_regmap = syscon_node_to_regmap(args.node);
|
|
- if (IS_ERR(priv->toprgu_regmap))
|
|
- return PTR_ERR(priv->toprgu_regmap);
|
|
- }
|
|
-
|
|
- /* check for switch first, otherwise phy will be used */
|
|
- priv->sw = SW_NONE;
|
|
- priv->switch_init = NULL;
|
|
- priv->switch_mac_control = NULL;
|
|
- str = dev_read_string(dev, "mediatek,switch");
|
|
-
|
|
- if (str) {
|
|
- if (!strcmp(str, "mt7530")) {
|
|
- priv->sw = SW_MT7530;
|
|
- priv->switch_init = mt7530_setup;
|
|
- priv->switch_mac_control = mt7530_mac_control;
|
|
- priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
|
|
- priv->mt753x_reset_wait_time = 1000;
|
|
- } else if (!strcmp(str, "mt7531")) {
|
|
- priv->sw = SW_MT7531;
|
|
- priv->switch_init = mt7531_setup;
|
|
- priv->switch_mac_control = mt7531_mac_control;
|
|
- priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
|
|
- priv->mt753x_reset_wait_time = 200;
|
|
- } else if (!strcmp(str, "mt7988")) {
|
|
- priv->sw = SW_MT7988;
|
|
- priv->switch_init = mt7988_setup;
|
|
- priv->switch_mac_control = mt7988_mac_control;
|
|
- priv->mt753x_smi_addr = MT753X_DFL_SMI_ADDR;
|
|
- priv->mt753x_reset_wait_time = 50;
|
|
- } else {
|
|
- printf("error: unsupported switch\n");
|
|
- return -EINVAL;
|
|
- }
|
|
-
|
|
- priv->mcm = dev_read_bool(dev, "mediatek,mcm");
|
|
- if (priv->mcm) {
|
|
- ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm);
|
|
- if (ret) {
|
|
- printf("error: no reset ctrl for mcm\n");
|
|
- return ret;
|
|
- }
|
|
- } else {
|
|
- gpio_request_by_name(dev, "reset-gpios", 0,
|
|
- &priv->rst_gpio, GPIOD_IS_OUT);
|
|
- }
|
|
- } else {
|
|
- ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
|
|
- 0, &args);
|
|
- if (ret) {
|
|
- printf("error: phy-handle is not specified\n");
|
|
- return ret;
|
|
- }
|
|
-
|
|
- priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
|
|
- if (priv->phy_addr < 0) {
|
|
- printf("error: phy address is not specified\n");
|
|
- return ret;
|
|
- }
|
|
- }
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-static const struct mtk_soc_data mt7988_data = {
|
|
- .caps = MT7988_CAPS,
|
|
- .ana_rgc3 = 0x128,
|
|
- .gdma_count = 3,
|
|
- .pdma_base = PDMA_V3_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma_v2),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma_v2),
|
|
-};
|
|
-
|
|
-static const struct mtk_soc_data mt7986_data = {
|
|
- .caps = MT7986_CAPS,
|
|
- .ana_rgc3 = 0x128,
|
|
- .gdma_count = 2,
|
|
- .pdma_base = PDMA_V2_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma_v2),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma_v2),
|
|
-};
|
|
-
|
|
-static const struct mtk_soc_data mt7981_data = {
|
|
- .caps = MT7981_CAPS,
|
|
- .ana_rgc3 = 0x128,
|
|
- .gdma_count = 2,
|
|
- .pdma_base = PDMA_V2_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma_v2),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma_v2),
|
|
-};
|
|
-
|
|
-static const struct mtk_soc_data mt7629_data = {
|
|
- .caps = MT7629_CAPS,
|
|
- .ana_rgc3 = 0x128,
|
|
- .gdma_count = 2,
|
|
- .pdma_base = PDMA_V1_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma),
|
|
-};
|
|
-
|
|
-static const struct mtk_soc_data mt7623_data = {
|
|
- .caps = MT7623_CAPS,
|
|
- .gdma_count = 2,
|
|
- .pdma_base = PDMA_V1_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma),
|
|
-};
|
|
-
|
|
-static const struct mtk_soc_data mt7622_data = {
|
|
- .caps = MT7622_CAPS,
|
|
- .ana_rgc3 = 0x2028,
|
|
- .gdma_count = 2,
|
|
- .pdma_base = PDMA_V1_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma),
|
|
-};
|
|
-
|
|
-static const struct mtk_soc_data mt7621_data = {
|
|
- .caps = MT7621_CAPS,
|
|
- .gdma_count = 2,
|
|
- .pdma_base = PDMA_V1_BASE,
|
|
- .txd_size = sizeof(struct mtk_tx_dma),
|
|
- .rxd_size = sizeof(struct mtk_rx_dma),
|
|
-};
|
|
-
|
|
-static const struct udevice_id mtk_eth_ids[] = {
|
|
- { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
|
|
- { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
|
|
- { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
|
|
- { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
|
|
- { .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
|
|
- { .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
|
|
- { .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
|
|
- {}
|
|
-};
|
|
-
|
|
-static const struct eth_ops mtk_eth_ops = {
|
|
- .start = mtk_eth_start,
|
|
- .stop = mtk_eth_stop,
|
|
- .send = mtk_eth_send,
|
|
- .recv = mtk_eth_recv,
|
|
- .free_pkt = mtk_eth_free_pkt,
|
|
- .write_hwaddr = mtk_eth_write_hwaddr,
|
|
-};
|
|
-
|
|
-U_BOOT_DRIVER(mtk_eth) = {
|
|
- .name = "mtk-eth",
|
|
- .id = UCLASS_ETH,
|
|
- .of_match = mtk_eth_ids,
|
|
- .of_to_plat = mtk_eth_of_to_plat,
|
|
- .plat_auto = sizeof(struct eth_pdata),
|
|
- .probe = mtk_eth_probe,
|
|
- .remove = mtk_eth_remove,
|
|
- .ops = &mtk_eth_ops,
|
|
- .priv_auto = sizeof(struct mtk_eth_priv),
|
|
- .flags = DM_FLAG_ALLOC_PRIV_DMA,
|
|
-};
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mtk_eth.c
|
|
@@ -0,0 +1,1563 @@
|
|
+// SPDX-License-Identifier: GPL-2.0
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#include <cpu_func.h>
|
|
+#include <dm.h>
|
|
+#include <log.h>
|
|
+#include <malloc.h>
|
|
+#include <miiphy.h>
|
|
+#include <net.h>
|
|
+#include <regmap.h>
|
|
+#include <reset.h>
|
|
+#include <syscon.h>
|
|
+#include <wait_bit.h>
|
|
+#include <asm/cache.h>
|
|
+#include <asm/gpio.h>
|
|
+#include <asm/io.h>
|
|
+#include <dm/device_compat.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/err.h>
|
|
+#include <linux/ioport.h>
|
|
+#include <linux/mdio.h>
|
|
+#include <linux/mii.h>
|
|
+#include <linux/printk.h>
|
|
+
|
|
+#include "mtk_eth.h"
|
|
+
|
|
+#define NUM_TX_DESC 32
|
|
+#define NUM_RX_DESC 32
|
|
+#define TX_TOTAL_BUF_SIZE (NUM_TX_DESC * PKTSIZE_ALIGN)
|
|
+#define RX_TOTAL_BUF_SIZE (NUM_RX_DESC * PKTSIZE_ALIGN)
|
|
+#define TOTAL_PKT_BUF_SIZE (TX_TOTAL_BUF_SIZE + RX_TOTAL_BUF_SIZE)
|
|
+
|
|
+#define GDMA_FWD_TO_CPU \
|
|
+ (0x20000000 | \
|
|
+ GDM_ICS_EN | \
|
|
+ GDM_TCS_EN | \
|
|
+ GDM_UCS_EN | \
|
|
+ STRP_CRC | \
|
|
+ (DP_PDMA << MYMAC_DP_S) | \
|
|
+ (DP_PDMA << BC_DP_S) | \
|
|
+ (DP_PDMA << MC_DP_S) | \
|
|
+ (DP_PDMA << UN_DP_S))
|
|
+
|
|
+#define GDMA_BRIDGE_TO_CPU \
|
|
+ (0xC0000000 | \
|
|
+ GDM_ICS_EN | \
|
|
+ GDM_TCS_EN | \
|
|
+ GDM_UCS_EN | \
|
|
+ (DP_PDMA << MYMAC_DP_S) | \
|
|
+ (DP_PDMA << BC_DP_S) | \
|
|
+ (DP_PDMA << MC_DP_S) | \
|
|
+ (DP_PDMA << UN_DP_S))
|
|
+
|
|
+#define GDMA_FWD_DISCARD \
|
|
+ (0x20000000 | \
|
|
+ GDM_ICS_EN | \
|
|
+ GDM_TCS_EN | \
|
|
+ GDM_UCS_EN | \
|
|
+ STRP_CRC | \
|
|
+ (DP_DISCARD << MYMAC_DP_S) | \
|
|
+ (DP_DISCARD << BC_DP_S) | \
|
|
+ (DP_DISCARD << MC_DP_S) | \
|
|
+ (DP_DISCARD << UN_DP_S))
|
|
+
|
|
+struct mtk_eth_priv {
|
|
+ char pkt_pool[TOTAL_PKT_BUF_SIZE] __aligned(ARCH_DMA_MINALIGN);
|
|
+
|
|
+ void *tx_ring_noc;
|
|
+ void *rx_ring_noc;
|
|
+
|
|
+ int rx_dma_owner_idx0;
|
|
+ int tx_cpu_owner_idx0;
|
|
+
|
|
+ void __iomem *fe_base;
|
|
+ void __iomem *gmac_base;
|
|
+ void __iomem *sgmii_base;
|
|
+
|
|
+ struct regmap *ethsys_regmap;
|
|
+
|
|
+ struct regmap *infra_regmap;
|
|
+
|
|
+ struct regmap *usxgmii_regmap;
|
|
+ struct regmap *xfi_pextp_regmap;
|
|
+ struct regmap *xfi_pll_regmap;
|
|
+ struct regmap *toprgu_regmap;
|
|
+
|
|
+ struct mii_dev *mdio_bus;
|
|
+
|
|
+ const struct mtk_soc_data *soc;
|
|
+ int gmac_id;
|
|
+ int force_mode;
|
|
+ int speed;
|
|
+ int duplex;
|
|
+ int mdc;
|
|
+ bool pn_swap;
|
|
+
|
|
+ struct phy_device *phydev;
|
|
+ int phy_interface;
|
|
+ int phy_addr;
|
|
+
|
|
+ struct mtk_eth_switch_priv *swpriv;
|
|
+ const char *swname;
|
|
+
|
|
+ struct gpio_desc rst_gpio;
|
|
+ int mcm;
|
|
+
|
|
+ struct reset_ctl rst_fe;
|
|
+ struct reset_ctl rst_mcm;
|
|
+};
|
|
+
|
|
+static void mtk_pdma_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
|
|
+{
|
|
+ writel(val, priv->fe_base + priv->soc->pdma_base + reg);
|
|
+}
|
|
+
|
|
+static void mtk_pdma_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
|
|
+ u32 set)
|
|
+{
|
|
+ clrsetbits_le32(priv->fe_base + priv->soc->pdma_base + reg, clr, set);
|
|
+}
|
|
+
|
|
+static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg,
|
|
+ u32 val)
|
|
+{
|
|
+ u32 gdma_base;
|
|
+
|
|
+ if (no == 2)
|
|
+ gdma_base = GDMA3_BASE;
|
|
+ else if (no == 1)
|
|
+ gdma_base = GDMA2_BASE;
|
|
+ else
|
|
+ gdma_base = GDMA1_BASE;
|
|
+
|
|
+ writel(val, priv->fe_base + gdma_base + reg);
|
|
+}
|
|
+
|
|
+void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
|
|
+{
|
|
+ clrsetbits_le32(priv->fe_base + reg, clr, set);
|
|
+}
|
|
+
|
|
+static u32 mtk_gmac_read(struct mtk_eth_priv *priv, u32 reg)
|
|
+{
|
|
+ return readl(priv->gmac_base + reg);
|
|
+}
|
|
+
|
|
+static void mtk_gmac_write(struct mtk_eth_priv *priv, u32 reg, u32 val)
|
|
+{
|
|
+ writel(val, priv->gmac_base + reg);
|
|
+}
|
|
+
|
|
+void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
|
|
+{
|
|
+ clrsetbits_le32(priv->gmac_base + reg, clr, set);
|
|
+}
|
|
+
|
|
+void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set)
|
|
+{
|
|
+ uint val;
|
|
+
|
|
+ regmap_read(priv->ethsys_regmap, reg, &val);
|
|
+ val &= ~clr;
|
|
+ val |= set;
|
|
+ regmap_write(priv->ethsys_regmap, reg, val);
|
|
+}
|
|
+
|
|
+static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
|
|
+ u32 set)
|
|
+{
|
|
+ uint val;
|
|
+
|
|
+ regmap_read(priv->infra_regmap, reg, &val);
|
|
+ val &= ~clr;
|
|
+ val |= set;
|
|
+ regmap_write(priv->infra_regmap, reg, val);
|
|
+}
|
|
+
|
|
+/* Direct MDIO clause 22/45 access via SoC */
|
|
+static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data,
|
|
+ u32 cmd, u32 st)
|
|
+{
|
|
+ int ret;
|
|
+ u32 val;
|
|
+
|
|
+ val = (st << MDIO_ST_S) |
|
|
+ ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
|
|
+ (((u32)phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
|
|
+ (((u32)reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
|
|
+
|
|
+ if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
|
|
+ val |= data & MDIO_RW_DATA_M;
|
|
+
|
|
+ mtk_gmac_write(priv, GMAC_PIAC_REG, val | PHY_ACS_ST);
|
|
+
|
|
+ ret = wait_for_bit_le32(priv->gmac_base + GMAC_PIAC_REG,
|
|
+ PHY_ACS_ST, 0, 5000, 0);
|
|
+ if (ret) {
|
|
+ pr_warn("MDIO access timeout\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
|
|
+ val = mtk_gmac_read(priv, GMAC_PIAC_REG);
|
|
+ return val & MDIO_RW_DATA_M;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Direct MDIO clause 22 read via SoC */
|
|
+int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg)
|
|
+{
|
|
+ return mtk_mii_rw(priv, phy, reg, 0, MDIO_CMD_READ, MDIO_ST_C22);
|
|
+}
|
|
+
|
|
+/* Direct MDIO clause 22 write via SoC */
|
|
+int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data)
|
|
+{
|
|
+ return mtk_mii_rw(priv, phy, reg, data, MDIO_CMD_WRITE, MDIO_ST_C22);
|
|
+}
|
|
+
|
|
+/* Direct MDIO clause 45 read via SoC */
|
|
+int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return mtk_mii_rw(priv, addr, devad, 0, MDIO_CMD_READ_C45,
|
|
+ MDIO_ST_C45);
|
|
+}
|
|
+
|
|
+/* Direct MDIO clause 45 write via SoC */
|
|
+int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
|
|
+ u16 val)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mtk_mii_rw(priv, addr, devad, reg, MDIO_CMD_ADDR, MDIO_ST_C45);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return mtk_mii_rw(priv, addr, devad, val, MDIO_CMD_WRITE,
|
|
+ MDIO_ST_C45);
|
|
+}
|
|
+
|
|
+/* Indirect MDIO clause 45 read via MII registers */
|
|
+int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
+ (MMD_ADDR << MMD_CMD_S) |
|
|
+ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
+ (MMD_DATA << MMD_CMD_S) |
|
|
+ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return mtk_mii_read(priv, addr, MII_MMD_ADDR_DATA_REG);
|
|
+}
|
|
+
|
|
+/* Indirect MDIO clause 45 write via MII registers */
|
|
+int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
|
|
+ u16 val)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
+ (MMD_ADDR << MMD_CMD_S) |
|
|
+ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, reg);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ ret = mtk_mii_write(priv, addr, MII_MMD_ACC_CTL_REG,
|
|
+ (MMD_DATA << MMD_CMD_S) |
|
|
+ ((devad << MMD_DEVAD_S) & MMD_DEVAD_M));
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ return mtk_mii_write(priv, addr, MII_MMD_ADDR_DATA_REG, val);
|
|
+}
|
|
+
|
|
+static int mtk_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = bus->priv;
|
|
+
|
|
+ if (devad < 0)
|
|
+ return mtk_mii_read(priv, addr, reg);
|
|
+
|
|
+ return mtk_mmd_read(priv, addr, devad, reg);
|
|
+}
|
|
+
|
|
+static int mtk_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
|
+ u16 val)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = bus->priv;
|
|
+
|
|
+ if (devad < 0)
|
|
+ return mtk_mii_write(priv, addr, reg, val);
|
|
+
|
|
+ return mtk_mmd_write(priv, addr, devad, reg, val);
|
|
+}
|
|
+
|
|
+static int mtk_mdio_register(struct udevice *dev)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ struct mii_dev *mdio_bus = mdio_alloc();
|
|
+ int ret;
|
|
+
|
|
+ if (!mdio_bus)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ mdio_bus->read = mtk_mdio_read;
|
|
+ mdio_bus->write = mtk_mdio_write;
|
|
+ snprintf(mdio_bus->name, sizeof(mdio_bus->name), dev->name);
|
|
+
|
|
+ mdio_bus->priv = (void *)priv;
|
|
+
|
|
+ ret = mdio_register(mdio_bus);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->mdio_bus = mdio_bus;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_switch_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ struct mtk_eth_switch *swdrvs = ll_entry_start(struct mtk_eth_switch,
|
|
+ mtk_eth_switch);
|
|
+ const u32 n_swdrvs = ll_entry_count(struct mtk_eth_switch,
|
|
+ mtk_eth_switch);
|
|
+ struct mtk_eth_switch *tmp, *swdrv = NULL;
|
|
+ u32 reset_wait_time = 500;
|
|
+ size_t priv_size;
|
|
+ int ret;
|
|
+
|
|
+ if (strcmp(priv->swname, "auto")) {
|
|
+ for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) {
|
|
+ if (!strcmp(tmp->name, priv->swname)) {
|
|
+ swdrv = tmp;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (swdrv)
|
|
+ reset_wait_time = swdrv->reset_wait_time;
|
|
+
|
|
+ /* Global reset switch */
|
|
+ if (priv->mcm) {
|
|
+ reset_assert(&priv->rst_mcm);
|
|
+ udelay(1000);
|
|
+ reset_deassert(&priv->rst_mcm);
|
|
+ mdelay(reset_wait_time);
|
|
+ } else if (dm_gpio_is_valid(&priv->rst_gpio)) {
|
|
+ dm_gpio_set_value(&priv->rst_gpio, 0);
|
|
+ udelay(1000);
|
|
+ dm_gpio_set_value(&priv->rst_gpio, 1);
|
|
+ mdelay(reset_wait_time);
|
|
+ }
|
|
+
|
|
+ if (!swdrv) {
|
|
+ for (tmp = swdrvs; tmp < swdrvs + n_swdrvs; tmp++) {
|
|
+ if (!tmp->detect)
|
|
+ continue;
|
|
+
|
|
+ ret = tmp->detect(priv);
|
|
+ if (!ret) {
|
|
+ swdrv = tmp;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!swdrv) {
|
|
+ printf("Error: unable to detect switch\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ } else {
|
|
+ if (swdrv->detect) {
|
|
+ ret = swdrv->detect(priv);
|
|
+ if (ret) {
|
|
+ printf("Error: switch probing failed\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ printf("%s\n", swdrv->desc);
|
|
+
|
|
+ priv_size = swdrv->priv_size;
|
|
+ if (priv_size < sizeof(struct mtk_eth_switch_priv))
|
|
+ priv_size = sizeof(struct mtk_eth_switch_priv);
|
|
+
|
|
+ priv->swpriv = calloc(1, priv_size);
|
|
+ if (!priv->swpriv) {
|
|
+ printf("Error: no memory for switch data\n");
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ priv->swpriv->eth = priv;
|
|
+ priv->swpriv->soc = priv->soc;
|
|
+ priv->swpriv->phy_interface = priv->phy_interface;
|
|
+ priv->swpriv->sw = swdrv;
|
|
+ priv->swpriv->ethsys_base = regmap_get_range(priv->ethsys_regmap, 0);
|
|
+
|
|
+ ret = swdrv->setup(priv->swpriv);
|
|
+ if (ret) {
|
|
+ free(priv->swpriv);
|
|
+ priv->swpriv = NULL;
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mtk_xphy_link_adjust(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ u16 lcl_adv = 0, rmt_adv = 0;
|
|
+ u8 flowctrl;
|
|
+ u32 mcr;
|
|
+
|
|
+ mcr = mtk_gmac_read(priv, XGMAC_PORT_MCR(priv->gmac_id));
|
|
+ mcr &= ~(XGMAC_FORCE_TX_FC | XGMAC_FORCE_RX_FC);
|
|
+
|
|
+ if (priv->phydev->duplex) {
|
|
+ if (priv->phydev->pause)
|
|
+ rmt_adv = LPA_PAUSE_CAP;
|
|
+ if (priv->phydev->asym_pause)
|
|
+ rmt_adv |= LPA_PAUSE_ASYM;
|
|
+
|
|
+ if (priv->phydev->advertising & ADVERTISED_Pause)
|
|
+ lcl_adv |= ADVERTISE_PAUSE_CAP;
|
|
+ if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
|
|
+ lcl_adv |= ADVERTISE_PAUSE_ASYM;
|
|
+
|
|
+ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
|
|
+
|
|
+ if (flowctrl & FLOW_CTRL_TX)
|
|
+ mcr |= XGMAC_FORCE_TX_FC;
|
|
+ if (flowctrl & FLOW_CTRL_RX)
|
|
+ mcr |= XGMAC_FORCE_RX_FC;
|
|
+
|
|
+ debug("rx pause %s, tx pause %s\n",
|
|
+ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
|
|
+ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
|
|
+ }
|
|
+
|
|
+ mcr &= ~(XGMAC_TRX_DISABLE);
|
|
+ mtk_gmac_write(priv, XGMAC_PORT_MCR(priv->gmac_id), mcr);
|
|
+}
|
|
+
|
|
+static void mtk_phy_link_adjust(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ u16 lcl_adv = 0, rmt_adv = 0;
|
|
+ u8 flowctrl;
|
|
+ u32 mcr;
|
|
+
|
|
+ mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
+ (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
|
|
+ MAC_MODE | FORCE_MODE |
|
|
+ MAC_TX_EN | MAC_RX_EN |
|
|
+ DEL_RXFIFO_CLR |
|
|
+ BKOFF_EN | BACKPR_EN;
|
|
+
|
|
+ switch (priv->phydev->speed) {
|
|
+ case SPEED_10:
|
|
+ mcr |= (SPEED_10M << FORCE_SPD_S);
|
|
+ break;
|
|
+ case SPEED_100:
|
|
+ mcr |= (SPEED_100M << FORCE_SPD_S);
|
|
+ break;
|
|
+ case SPEED_1000:
|
|
+ case SPEED_2500:
|
|
+ mcr |= (SPEED_1000M << FORCE_SPD_S);
|
|
+ break;
|
|
+ };
|
|
+
|
|
+ if (priv->phydev->link)
|
|
+ mcr |= FORCE_LINK;
|
|
+
|
|
+ if (priv->phydev->duplex) {
|
|
+ mcr |= FORCE_DPX;
|
|
+
|
|
+ if (priv->phydev->pause)
|
|
+ rmt_adv = LPA_PAUSE_CAP;
|
|
+ if (priv->phydev->asym_pause)
|
|
+ rmt_adv |= LPA_PAUSE_ASYM;
|
|
+
|
|
+ if (priv->phydev->advertising & ADVERTISED_Pause)
|
|
+ lcl_adv |= ADVERTISE_PAUSE_CAP;
|
|
+ if (priv->phydev->advertising & ADVERTISED_Asym_Pause)
|
|
+ lcl_adv |= ADVERTISE_PAUSE_ASYM;
|
|
+
|
|
+ flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
|
|
+
|
|
+ if (flowctrl & FLOW_CTRL_TX)
|
|
+ mcr |= FORCE_TX_FC;
|
|
+ if (flowctrl & FLOW_CTRL_RX)
|
|
+ mcr |= FORCE_RX_FC;
|
|
+
|
|
+ debug("rx pause %s, tx pause %s\n",
|
|
+ flowctrl & FLOW_CTRL_RX ? "enabled" : "disabled",
|
|
+ flowctrl & FLOW_CTRL_TX ? "enabled" : "disabled");
|
|
+ }
|
|
+
|
|
+ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
|
|
+}
|
|
+
|
|
+static int mtk_phy_start(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ struct phy_device *phydev = priv->phydev;
|
|
+ int ret;
|
|
+
|
|
+ ret = phy_startup(phydev);
|
|
+
|
|
+ if (ret) {
|
|
+ debug("Could not initialize PHY %s\n", phydev->dev->name);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (!phydev->link) {
|
|
+ debug("%s: link down.\n", phydev->dev->name);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!priv->force_mode) {
|
|
+ if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
|
|
+ mtk_xphy_link_adjust(priv);
|
|
+ else
|
|
+ mtk_phy_link_adjust(priv);
|
|
+ }
|
|
+
|
|
+ debug("Speed: %d, %s duplex%s\n", phydev->speed,
|
|
+ (phydev->duplex) ? "full" : "half",
|
|
+ (phydev->port == PORT_FIBRE) ? ", fiber mode" : "");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_phy_probe(struct udevice *dev)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ struct phy_device *phydev;
|
|
+
|
|
+ phydev = phy_connect(priv->mdio_bus, priv->phy_addr, dev,
|
|
+ priv->phy_interface);
|
|
+ if (!phydev)
|
|
+ return -ENODEV;
|
|
+
|
|
+ phydev->supported &= PHY_GBIT_FEATURES;
|
|
+ phydev->advertising = phydev->supported;
|
|
+
|
|
+ priv->phydev = phydev;
|
|
+ phy_config(phydev);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mtk_sgmii_an_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ /* Set SGMII GEN1 speed(1G) */
|
|
+ clrbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, SGMSYS_SPEED_MASK);
|
|
+
|
|
+ /* Enable SGMII AN */
|
|
+ setbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
|
|
+ SGMII_AN_ENABLE);
|
|
+
|
|
+ /* SGMII AN mode setting */
|
|
+ writel(SGMII_AN_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
|
|
+
|
|
+ /* SGMII PN SWAP setting */
|
|
+ if (priv->pn_swap) {
|
|
+ setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
|
|
+ SGMII_PN_SWAP_TX_RX);
|
|
+ }
|
|
+
|
|
+ /* Release PHYA power down state */
|
|
+ clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
|
|
+ SGMII_PHYA_PWD, 0);
|
|
+}
|
|
+
|
|
+static void mtk_sgmii_force_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ /* Set SGMII GEN2 speed(2.5G) */
|
|
+ clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3,
|
|
+ SGMSYS_SPEED_MASK,
|
|
+ FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
|
|
+
|
|
+ /* Disable SGMII AN */
|
|
+ clrsetbits_le32(priv->sgmii_base + SGMSYS_PCS_CONTROL_1,
|
|
+ SGMII_AN_ENABLE, 0);
|
|
+
|
|
+ /* SGMII force mode setting */
|
|
+ writel(SGMII_FORCE_MODE, priv->sgmii_base + SGMSYS_SGMII_MODE);
|
|
+
|
|
+ /* SGMII PN SWAP setting */
|
|
+ if (priv->pn_swap) {
|
|
+ setbits_le32(priv->sgmii_base + SGMSYS_QPHY_WRAP_CTRL,
|
|
+ SGMII_PN_SWAP_TX_RX);
|
|
+ }
|
|
+
|
|
+ /* Release PHYA power down state */
|
|
+ clrsetbits_le32(priv->sgmii_base + SGMSYS_QPHY_PWR_STATE_CTRL,
|
|
+ SGMII_PHYA_PWD, 0);
|
|
+}
|
|
+
|
|
+static void mtk_xfi_pll_enable(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ u32 val = 0;
|
|
+
|
|
+ /* Add software workaround for USXGMII PLL TCL issue */
|
|
+ regmap_write(priv->xfi_pll_regmap, XFI_PLL_ANA_GLB8,
|
|
+ RG_XFI_PLL_ANA_SWWA);
|
|
+
|
|
+ regmap_read(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, &val);
|
|
+ val |= RG_XFI_PLL_EN;
|
|
+ regmap_write(priv->xfi_pll_regmap, XFI_PLL_DIG_GLB8, val);
|
|
+}
|
|
+
|
|
+static void mtk_usxgmii_reset(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ switch (priv->gmac_id) {
|
|
+ case 1:
|
|
+ regmap_write(priv->toprgu_regmap, 0xFC, 0x0000A004);
|
|
+ regmap_write(priv->toprgu_regmap, 0x18, 0x88F0A004);
|
|
+ regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
|
|
+ regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
|
|
+ regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
|
|
+ break;
|
|
+ case 2:
|
|
+ regmap_write(priv->toprgu_regmap, 0xFC, 0x00005002);
|
|
+ regmap_write(priv->toprgu_regmap, 0x18, 0x88F05002);
|
|
+ regmap_write(priv->toprgu_regmap, 0xFC, 0x00000000);
|
|
+ regmap_write(priv->toprgu_regmap, 0x18, 0x88F00000);
|
|
+ regmap_write(priv->toprgu_regmap, 0x18, 0x00F00000);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ mdelay(10);
|
|
+}
|
|
+
|
|
+static void mtk_usxgmii_setup_phya_an_10000(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6D);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x80C, 0x30000000);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x80C, 0x10000000);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x80C, 0x00000000);
|
|
+
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x40704000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3050, 0xA8000000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x000000AA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
|
|
+ udelay(150);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
|
|
+ udelay(15);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
|
|
+ udelay(100);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
|
|
+ udelay(400);
|
|
+}
|
|
+
|
|
+static void mtk_usxgmii_setup_phya_force_10000(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ regmap_write(priv->usxgmii_regmap, 0x810, 0x000FFE6C);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x818, 0x07B1EC7B);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x80C, 0xB0000000);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->usxgmii_regmap, 0x80C, 0x90000000);
|
|
+ ndelay(1020);
|
|
+
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x9024, 0x00C9071C);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2020, 0xAA8585AA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2030, 0x0C020707);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2034, 0x0E050F0F);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x2040, 0x00140032);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50F0, 0x00C014AA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50E0, 0x3777C12B);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x506C, 0x005F9CFF);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5070, 0x9D9DFAFA);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5074, 0x27273F3F);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5078, 0xA7883C68);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x507C, 0x11661166);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5080, 0x0E000AAF);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5084, 0x08080D0D);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5088, 0x02030909);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50E4, 0x0C0C0000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50E8, 0x04040000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50EC, 0x0F0F0C06);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50A8, 0x506E8C8C);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x6004, 0x18190000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x00F8, 0x01423342);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F20);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0030, 0x00050C00);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x02002800);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3028, 0x00008A01);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x302C, 0x0000A884);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3024, 0x00083002);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3010, 0x00022220);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x5064, 0x0F020A01);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x50B4, 0x06100600);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3048, 0x47684100);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3050, 0x00000000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3054, 0x00000000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x306C, 0x00000F00);
|
|
+ if (priv->gmac_id == 2)
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0xA008, 0x0007B400);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0xA060, 0x00040000);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x90D0, 0x00000001);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200E800);
|
|
+ udelay(150);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C111);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0200C101);
|
|
+ udelay(15);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C111);
|
|
+ ndelay(1020);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x0070, 0x0202C101);
|
|
+ udelay(100);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x30B0, 0x00000030);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x00F4, 0x80201F00);
|
|
+ regmap_write(priv->xfi_pextp_regmap, 0x3040, 0x30000000);
|
|
+ udelay(400);
|
|
+}
|
|
+
|
|
+static void mtk_usxgmii_an_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ mtk_xfi_pll_enable(priv);
|
|
+ mtk_usxgmii_reset(priv);
|
|
+ mtk_usxgmii_setup_phya_an_10000(priv);
|
|
+}
|
|
+
|
|
+static void mtk_10gbaser_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ mtk_xfi_pll_enable(priv);
|
|
+ mtk_usxgmii_reset(priv);
|
|
+ mtk_usxgmii_setup_phya_force_10000(priv);
|
|
+}
|
|
+
|
|
+static int mtk_mac_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ int i, sgmii_sel_mask = 0, ge_mode = 0;
|
|
+ u32 mcr;
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7629_GMAC2)) {
|
|
+ mtk_infra_rmw(priv, MT7629_INFRA_MISC2_REG,
|
|
+ INFRA_MISC2_BONDING_OPTION, priv->gmac_id);
|
|
+ }
|
|
+
|
|
+ switch (priv->phy_interface) {
|
|
+ case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ ge_mode = GE_MODE_RGMII;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_SGMII:
|
|
+ case PHY_INTERFACE_MODE_2500BASEX:
|
|
+ if (!IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
|
|
+ printf("Error: SGMII is not supported on this platform\n");
|
|
+ return -ENOTSUPP;
|
|
+ }
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC2_U3_QPHY)) {
|
|
+ mtk_infra_rmw(priv, USB_PHY_SWITCH_REG, QPHY_SEL_MASK,
|
|
+ SGMII_QPHY_SEL);
|
|
+ }
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_ETH_PATH_MT7622_SGMII))
|
|
+ sgmii_sel_mask = SYSCFG1_SGMII_SEL_M;
|
|
+
|
|
+ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG, sgmii_sel_mask,
|
|
+ SYSCFG1_SGMII_SEL(priv->gmac_id));
|
|
+
|
|
+ if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
|
|
+ mtk_sgmii_an_init(priv);
|
|
+ else
|
|
+ mtk_sgmii_force_init(priv);
|
|
+
|
|
+ ge_mode = GE_MODE_RGMII;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_MII:
|
|
+ case PHY_INTERFACE_MODE_GMII:
|
|
+ ge_mode = GE_MODE_MII;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RMII:
|
|
+ ge_mode = GE_MODE_RMII;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* set the gmac to the right mode */
|
|
+ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
|
|
+ SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
|
|
+ ge_mode << SYSCFG1_GE_MODE_S(priv->gmac_id));
|
|
+
|
|
+ if (priv->force_mode) {
|
|
+ mcr = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
|
+ (MAC_RX_PKT_LEN_1536 << MAC_RX_PKT_LEN_S) |
|
|
+ MAC_MODE | FORCE_MODE |
|
|
+ MAC_TX_EN | MAC_RX_EN |
|
|
+ BKOFF_EN | BACKPR_EN |
|
|
+ FORCE_LINK;
|
|
+
|
|
+ switch (priv->speed) {
|
|
+ case SPEED_10:
|
|
+ mcr |= SPEED_10M << FORCE_SPD_S;
|
|
+ break;
|
|
+ case SPEED_100:
|
|
+ mcr |= SPEED_100M << FORCE_SPD_S;
|
|
+ break;
|
|
+ case SPEED_1000:
|
|
+ case SPEED_2500:
|
|
+ mcr |= SPEED_1000M << FORCE_SPD_S;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (priv->duplex)
|
|
+ mcr |= FORCE_DPX;
|
|
+
|
|
+ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), mcr);
|
|
+ }
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_GMAC1_TRGMII) &&
|
|
+ !MTK_HAS_CAPS(priv->soc->caps, MTK_TRGMII_MT7621_CLK)) {
|
|
+ /* Lower Tx Driving for TRGMII path */
|
|
+ for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
|
|
+ mtk_gmac_write(priv, GMAC_TRGMII_TD_ODT(i),
|
|
+ (8 << TD_DM_DRVP_S) |
|
|
+ (8 << TD_DM_DRVN_S));
|
|
+
|
|
+ mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, 0,
|
|
+ RX_RST | RXC_DQSISEL);
|
|
+ mtk_gmac_rmw(priv, GMAC_TRGMII_RCK_CTRL, RX_RST, 0);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_xmac_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ u32 force_link = 0;
|
|
+
|
|
+ if (!IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
|
|
+ printf("Error: 10Gb interface is not supported on this platform\n");
|
|
+ return -ENOTSUPP;
|
|
+ }
|
|
+
|
|
+ switch (priv->phy_interface) {
|
|
+ case PHY_INTERFACE_MODE_USXGMII:
|
|
+ mtk_usxgmii_an_init(priv);
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_10GBASER:
|
|
+ mtk_10gbaser_init(priv);
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Set GMAC to the correct mode */
|
|
+ mtk_ethsys_rmw(priv, ETHSYS_SYSCFG1_REG,
|
|
+ SYSCFG1_GE_MODE_M << SYSCFG1_GE_MODE_S(priv->gmac_id),
|
|
+ 0);
|
|
+
|
|
+ if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
|
|
+ priv->gmac_id == 1) {
|
|
+ mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX,
|
|
+ NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL);
|
|
+ }
|
|
+
|
|
+ if (priv->phy_interface == PHY_INTERFACE_MODE_XGMII ||
|
|
+ priv->gmac_id == 2)
|
|
+ force_link = XGMAC_FORCE_LINK(priv->gmac_id);
|
|
+
|
|
+ mtk_gmac_rmw(priv, XGMAC_STS(priv->gmac_id),
|
|
+ XGMAC_FORCE_LINK(priv->gmac_id), force_link);
|
|
+
|
|
+ /* Force GMAC link down */
|
|
+ mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mtk_eth_fifo_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ char *pkt_base = priv->pkt_pool;
|
|
+ struct mtk_tx_dma_v2 *txd;
|
|
+ struct mtk_rx_dma_v2 *rxd;
|
|
+ int i;
|
|
+
|
|
+ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0xffff0000, 0);
|
|
+ udelay(500);
|
|
+
|
|
+ memset(priv->tx_ring_noc, 0, NUM_TX_DESC * priv->soc->txd_size);
|
|
+ memset(priv->rx_ring_noc, 0, NUM_RX_DESC * priv->soc->rxd_size);
|
|
+ memset(priv->pkt_pool, 0xff, TOTAL_PKT_BUF_SIZE);
|
|
+
|
|
+ flush_dcache_range((ulong)pkt_base,
|
|
+ (ulong)(pkt_base + TOTAL_PKT_BUF_SIZE));
|
|
+
|
|
+ priv->rx_dma_owner_idx0 = 0;
|
|
+ priv->tx_cpu_owner_idx0 = 0;
|
|
+
|
|
+ for (i = 0; i < NUM_TX_DESC; i++) {
|
|
+ txd = priv->tx_ring_noc + i * priv->soc->txd_size;
|
|
+
|
|
+ txd->txd1 = virt_to_phys(pkt_base);
|
|
+ txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0;
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id == 2 ?
|
|
+ 15 : priv->gmac_id + 1);
|
|
+ else if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2))
|
|
+ txd->txd5 = PDMA_V2_TXD5_FPORT_SET(priv->gmac_id + 1);
|
|
+ else
|
|
+ txd->txd4 = PDMA_V1_TXD4_FPORT_SET(priv->gmac_id + 1);
|
|
+
|
|
+ pkt_base += PKTSIZE_ALIGN;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < NUM_RX_DESC; i++) {
|
|
+ rxd = priv->rx_ring_noc + i * priv->soc->rxd_size;
|
|
+
|
|
+ rxd->rxd1 = virt_to_phys(pkt_base);
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
+ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
+ else
|
|
+ rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
+
|
|
+ pkt_base += PKTSIZE_ALIGN;
|
|
+ }
|
|
+
|
|
+ mtk_pdma_write(priv, TX_BASE_PTR_REG(0),
|
|
+ virt_to_phys(priv->tx_ring_noc));
|
|
+ mtk_pdma_write(priv, TX_MAX_CNT_REG(0), NUM_TX_DESC);
|
|
+ mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
|
|
+
|
|
+ mtk_pdma_write(priv, RX_BASE_PTR_REG(0),
|
|
+ virt_to_phys(priv->rx_ring_noc));
|
|
+ mtk_pdma_write(priv, RX_MAX_CNT_REG(0), NUM_RX_DESC);
|
|
+ mtk_pdma_write(priv, RX_CRX_IDX_REG(0), NUM_RX_DESC - 1);
|
|
+
|
|
+ mtk_pdma_write(priv, PDMA_RST_IDX_REG, RST_DTX_IDX0 | RST_DRX_IDX0);
|
|
+}
|
|
+
|
|
+static void mtk_eth_mdc_init(struct mtk_eth_priv *priv)
|
|
+{
|
|
+ u32 divider;
|
|
+
|
|
+ if (priv->mdc == 0)
|
|
+ return;
|
|
+
|
|
+ divider = min_t(u32, DIV_ROUND_UP(MDC_MAX_FREQ, priv->mdc), MDC_MAX_DIVIDER);
|
|
+
|
|
+ /* Configure MDC turbo mode */
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, MISC_MDC_TURBO);
|
|
+ else
|
|
+ mtk_gmac_rmw(priv, GMAC_PPSC_REG, 0, MISC_MDC_TURBO);
|
|
+
|
|
+ /* Configure MDC divider */
|
|
+ mtk_gmac_rmw(priv, GMAC_PPSC_REG, PHY_MDC_CFG,
|
|
+ FIELD_PREP(PHY_MDC_CFG, divider));
|
|
+}
|
|
+
|
|
+static int mtk_eth_start(struct udevice *dev)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ int i, ret;
|
|
+
|
|
+ /* Reset FE */
|
|
+ reset_assert(&priv->rst_fe);
|
|
+ udelay(1000);
|
|
+ reset_deassert(&priv->rst_fe);
|
|
+ mdelay(10);
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
+ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ setbits_le32(priv->fe_base + FE_GLO_MISC_REG, PDMA_VER_V2);
|
|
+
|
|
+ /* Packets forward to PDMA */
|
|
+ mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG, GDMA_FWD_TO_CPU);
|
|
+
|
|
+ for (i = 0; i < priv->soc->gdma_count; i++) {
|
|
+ if (i == priv->gmac_id)
|
|
+ continue;
|
|
+
|
|
+ mtk_gdma_write(priv, i, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD);
|
|
+ }
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3)) {
|
|
+ if (priv->swpriv && !strcmp(priv->swpriv->sw->name, "mt7988") &&
|
|
+ priv->gmac_id == 0) {
|
|
+ mtk_gdma_write(priv, priv->gmac_id, GDMA_IG_CTRL_REG,
|
|
+ GDMA_BRIDGE_TO_CPU);
|
|
+
|
|
+ mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
|
|
+ GDMA_CPU_BRIDGE_EN);
|
|
+ } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_XGMII) &&
|
|
+ priv->gmac_id != 0) {
|
|
+ mtk_gdma_write(priv, priv->gmac_id, GDMA_EG_CTRL_REG,
|
|
+ GDMA_CPU_BRIDGE_EN);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ udelay(500);
|
|
+
|
|
+ mtk_eth_fifo_init(priv);
|
|
+
|
|
+ if (priv->swpriv) {
|
|
+ /* Enable communication with switch */
|
|
+ if (priv->swpriv->sw->mac_control)
|
|
+ priv->swpriv->sw->mac_control(priv->swpriv, true);
|
|
+ } else {
|
|
+ /* Start PHY */
|
|
+ ret = mtk_phy_start(priv);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG, 0,
|
|
+ TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN);
|
|
+ udelay(500);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void mtk_eth_stop(struct udevice *dev)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+
|
|
+ if (priv->swpriv) {
|
|
+ if (priv->swpriv->sw->mac_control)
|
|
+ priv->swpriv->sw->mac_control(priv->swpriv, false);
|
|
+ }
|
|
+
|
|
+ mtk_pdma_rmw(priv, PDMA_GLO_CFG_REG,
|
|
+ TX_WB_DDONE | RX_DMA_EN | TX_DMA_EN, 0);
|
|
+ udelay(500);
|
|
+
|
|
+ wait_for_bit_le32(priv->fe_base + priv->soc->pdma_base + PDMA_GLO_CFG_REG,
|
|
+ RX_DMA_BUSY | TX_DMA_BUSY, 0, 5000, 0);
|
|
+}
|
|
+
|
|
+static int mtk_eth_write_hwaddr(struct udevice *dev)
|
|
+{
|
|
+ struct eth_pdata *pdata = dev_get_plat(dev);
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ unsigned char *mac = pdata->enetaddr;
|
|
+ u32 macaddr_lsb, macaddr_msb;
|
|
+
|
|
+ macaddr_msb = ((u32)mac[0] << 8) | (u32)mac[1];
|
|
+ macaddr_lsb = ((u32)mac[2] << 24) | ((u32)mac[3] << 16) |
|
|
+ ((u32)mac[4] << 8) | (u32)mac[5];
|
|
+
|
|
+ mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_MSB_REG, macaddr_msb);
|
|
+ mtk_gdma_write(priv, priv->gmac_id, GDMA_MAC_LSB_REG, macaddr_lsb);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_eth_send(struct udevice *dev, void *packet, int length)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ u32 idx = priv->tx_cpu_owner_idx0;
|
|
+ struct mtk_tx_dma_v2 *txd;
|
|
+ void *pkt_base;
|
|
+
|
|
+ txd = priv->tx_ring_noc + idx * priv->soc->txd_size;
|
|
+
|
|
+ if (!(txd->txd2 & PDMA_TXD2_DDONE)) {
|
|
+ debug("mtk-eth: TX DMA descriptor ring is full\n");
|
|
+ return -EPERM;
|
|
+ }
|
|
+
|
|
+ pkt_base = (void *)phys_to_virt(txd->txd1);
|
|
+ memcpy(pkt_base, packet, length);
|
|
+ flush_dcache_range((ulong)pkt_base, (ulong)pkt_base +
|
|
+ roundup(length, ARCH_DMA_MINALIGN));
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
+ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ txd->txd2 = PDMA_TXD2_LS0 | PDMA_V2_TXD2_SDL0_SET(length);
|
|
+ else
|
|
+ txd->txd2 = PDMA_TXD2_LS0 | PDMA_V1_TXD2_SDL0_SET(length);
|
|
+
|
|
+ priv->tx_cpu_owner_idx0 = (priv->tx_cpu_owner_idx0 + 1) % NUM_TX_DESC;
|
|
+ mtk_pdma_write(priv, TX_CTX_IDX_REG(0), priv->tx_cpu_owner_idx0);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ u32 idx = priv->rx_dma_owner_idx0;
|
|
+ struct mtk_rx_dma_v2 *rxd;
|
|
+ uchar *pkt_base;
|
|
+ u32 length;
|
|
+
|
|
+ rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
|
|
+
|
|
+ if (!(rxd->rxd2 & PDMA_RXD2_DDONE)) {
|
|
+ debug("mtk-eth: RX DMA descriptor ring is empty\n");
|
|
+ return -EAGAIN;
|
|
+ }
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
+ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ length = PDMA_V2_RXD2_PLEN0_GET(rxd->rxd2);
|
|
+ else
|
|
+ length = PDMA_V1_RXD2_PLEN0_GET(rxd->rxd2);
|
|
+
|
|
+ pkt_base = (void *)phys_to_virt(rxd->rxd1);
|
|
+ invalidate_dcache_range((ulong)pkt_base, (ulong)pkt_base +
|
|
+ roundup(length, ARCH_DMA_MINALIGN));
|
|
+
|
|
+ if (packetp)
|
|
+ *packetp = pkt_base;
|
|
+
|
|
+ return length;
|
|
+}
|
|
+
|
|
+static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ u32 idx = priv->rx_dma_owner_idx0;
|
|
+ struct mtk_rx_dma_v2 *rxd;
|
|
+
|
|
+ rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size;
|
|
+
|
|
+ invalidate_dcache_range((ulong)rxd->rxd1,
|
|
+ (ulong)rxd->rxd1 + PKTSIZE_ALIGN);
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2) ||
|
|
+ MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V3))
|
|
+ rxd->rxd2 = PDMA_V2_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
+ else
|
|
+ rxd->rxd2 = PDMA_V1_RXD2_PLEN0_SET(PKTSIZE_ALIGN);
|
|
+
|
|
+ mtk_pdma_write(priv, RX_CRX_IDX_REG(0), idx);
|
|
+ priv->rx_dma_owner_idx0 = (priv->rx_dma_owner_idx0 + 1) % NUM_RX_DESC;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_eth_probe(struct udevice *dev)
|
|
+{
|
|
+ struct eth_pdata *pdata = dev_get_plat(dev);
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ ulong iobase = pdata->iobase;
|
|
+ int ret;
|
|
+
|
|
+ /* Frame Engine Register Base */
|
|
+ priv->fe_base = (void *)iobase;
|
|
+
|
|
+ /* GMAC Register Base */
|
|
+ priv->gmac_base = (void *)(iobase + GMAC_BASE);
|
|
+
|
|
+ /* MDIO register */
|
|
+ ret = mtk_mdio_register(dev);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Prepare for tx/rx rings */
|
|
+ priv->tx_ring_noc = (void *)
|
|
+ noncached_alloc(priv->soc->txd_size * NUM_TX_DESC,
|
|
+ ARCH_DMA_MINALIGN);
|
|
+ priv->rx_ring_noc = (void *)
|
|
+ noncached_alloc(priv->soc->rxd_size * NUM_RX_DESC,
|
|
+ ARCH_DMA_MINALIGN);
|
|
+
|
|
+ /* Set MDC divider */
|
|
+ mtk_eth_mdc_init(priv);
|
|
+
|
|
+ /* Set MAC mode */
|
|
+ if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_XGMII)
|
|
+ ret = mtk_xmac_init(priv);
|
|
+ else
|
|
+ ret = mtk_mac_init(priv);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ /* Probe phy if switch is not specified */
|
|
+ if (!priv->swname)
|
|
+ return mtk_phy_probe(dev);
|
|
+
|
|
+ /* Initialize switch */
|
|
+ return mtk_switch_init(priv);
|
|
+}
|
|
+
|
|
+static int mtk_eth_remove(struct udevice *dev)
|
|
+{
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+
|
|
+ /* MDIO unregister */
|
|
+ mdio_unregister(priv->mdio_bus);
|
|
+ mdio_free(priv->mdio_bus);
|
|
+
|
|
+ /* Stop possibly started DMA */
|
|
+ mtk_eth_stop(dev);
|
|
+
|
|
+ if (priv->swpriv) {
|
|
+ if (priv->swpriv->sw->cleanup)
|
|
+ priv->swpriv->sw->cleanup(priv->swpriv);
|
|
+ free(priv->swpriv);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int mtk_eth_of_to_plat(struct udevice *dev)
|
|
+{
|
|
+ struct eth_pdata *pdata = dev_get_plat(dev);
|
|
+ struct mtk_eth_priv *priv = dev_get_priv(dev);
|
|
+ struct ofnode_phandle_args args;
|
|
+ struct regmap *regmap;
|
|
+ ofnode subnode;
|
|
+ int ret;
|
|
+
|
|
+ priv->soc = (const struct mtk_soc_data *)dev_get_driver_data(dev);
|
|
+ if (!priv->soc) {
|
|
+ dev_err(dev, "missing soc compatible data\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ pdata->iobase = (phys_addr_t)dev_remap_addr(dev);
|
|
+
|
|
+ /* get corresponding ethsys phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,ethsys", NULL, 0, 0,
|
|
+ &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->ethsys_regmap = syscon_node_to_regmap(args.node);
|
|
+ if (IS_ERR(priv->ethsys_regmap))
|
|
+ return PTR_ERR(priv->ethsys_regmap);
|
|
+
|
|
+ if (MTK_HAS_CAPS(priv->soc->caps, MTK_INFRA)) {
|
|
+ /* get corresponding infracfg phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,infracfg",
|
|
+ NULL, 0, 0, &args);
|
|
+
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->infra_regmap = syscon_node_to_regmap(args.node);
|
|
+ if (IS_ERR(priv->infra_regmap))
|
|
+ return PTR_ERR(priv->infra_regmap);
|
|
+ }
|
|
+
|
|
+ /* Reset controllers */
|
|
+ ret = reset_get_by_name(dev, "fe", &priv->rst_fe);
|
|
+ if (ret) {
|
|
+ printf("error: Unable to get reset ctrl for frame engine\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ priv->gmac_id = dev_read_u32_default(dev, "mediatek,gmac-id", 0);
|
|
+
|
|
+ priv->mdc = 0;
|
|
+ subnode = ofnode_find_subnode(dev_ofnode(dev), "mdio");
|
|
+ if (ofnode_valid(subnode)) {
|
|
+ priv->mdc = ofnode_read_u32_default(subnode, "clock-frequency", 2500000);
|
|
+ if (priv->mdc > MDC_MAX_FREQ ||
|
|
+ priv->mdc < MDC_MAX_FREQ / MDC_MAX_DIVIDER) {
|
|
+ printf("error: MDIO clock frequency out of range\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Interface mode is required */
|
|
+ pdata->phy_interface = dev_read_phy_mode(dev);
|
|
+ priv->phy_interface = pdata->phy_interface;
|
|
+ if (pdata->phy_interface == PHY_INTERFACE_MODE_NA) {
|
|
+ printf("error: phy-mode is not set\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* Force mode or autoneg */
|
|
+ subnode = ofnode_find_subnode(dev_ofnode(dev), "fixed-link");
|
|
+ if (ofnode_valid(subnode)) {
|
|
+ priv->force_mode = 1;
|
|
+ priv->speed = ofnode_read_u32_default(subnode, "speed", 0);
|
|
+ priv->duplex = ofnode_read_bool(subnode, "full-duplex");
|
|
+
|
|
+ if (priv->speed != SPEED_10 && priv->speed != SPEED_100 &&
|
|
+ priv->speed != SPEED_1000 && priv->speed != SPEED_2500 &&
|
|
+ priv->speed != SPEED_10000) {
|
|
+ printf("error: no valid speed set in fixed-link\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if ((priv->phy_interface == PHY_INTERFACE_MODE_SGMII ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) &&
|
|
+ IS_ENABLED(CONFIG_MTK_ETH_SGMII)) {
|
|
+ /* get corresponding sgmii phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys",
|
|
+ NULL, 0, 0, &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ regmap = syscon_node_to_regmap(args.node);
|
|
+
|
|
+ if (IS_ERR(regmap))
|
|
+ return PTR_ERR(regmap);
|
|
+
|
|
+ priv->sgmii_base = regmap_get_range(regmap, 0);
|
|
+
|
|
+ if (!priv->sgmii_base) {
|
|
+ dev_err(dev, "Unable to find sgmii\n");
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ /* Upstream linux use mediatek,pnswap instead of pn_swap */
|
|
+ priv->pn_swap = ofnode_read_bool(args.node, "pn_swap") ||
|
|
+ ofnode_read_bool(args.node, "mediatek,pnswap");
|
|
+ } else if ((priv->phy_interface == PHY_INTERFACE_MODE_USXGMII ||
|
|
+ priv->phy_interface == PHY_INTERFACE_MODE_10GBASER) &&
|
|
+ IS_ENABLED(CONFIG_MTK_ETH_XGMII)) {
|
|
+ /* get corresponding usxgmii phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,usxgmiisys",
|
|
+ NULL, 0, 0, &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->usxgmii_regmap = syscon_node_to_regmap(args.node);
|
|
+ if (IS_ERR(priv->usxgmii_regmap))
|
|
+ return PTR_ERR(priv->usxgmii_regmap);
|
|
+
|
|
+ /* get corresponding xfi_pextp phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pextp",
|
|
+ NULL, 0, 0, &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->xfi_pextp_regmap = syscon_node_to_regmap(args.node);
|
|
+ if (IS_ERR(priv->xfi_pextp_regmap))
|
|
+ return PTR_ERR(priv->xfi_pextp_regmap);
|
|
+
|
|
+ /* get corresponding xfi_pll phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,xfi_pll",
|
|
+ NULL, 0, 0, &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->xfi_pll_regmap = syscon_node_to_regmap(args.node);
|
|
+ if (IS_ERR(priv->xfi_pll_regmap))
|
|
+ return PTR_ERR(priv->xfi_pll_regmap);
|
|
+
|
|
+ /* get corresponding toprgu phandle */
|
|
+ ret = dev_read_phandle_with_args(dev, "mediatek,toprgu",
|
|
+ NULL, 0, 0, &args);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+
|
|
+ priv->toprgu_regmap = syscon_node_to_regmap(args.node);
|
|
+ if (IS_ERR(priv->toprgu_regmap))
|
|
+ return PTR_ERR(priv->toprgu_regmap);
|
|
+ }
|
|
+
|
|
+ priv->swname = dev_read_string(dev, "mediatek,switch");
|
|
+ if (priv->swname) {
|
|
+ priv->mcm = dev_read_bool(dev, "mediatek,mcm");
|
|
+ if (priv->mcm) {
|
|
+ ret = reset_get_by_name(dev, "mcm", &priv->rst_mcm);
|
|
+ if (ret) {
|
|
+ printf("error: no reset ctrl for mcm\n");
|
|
+ return ret;
|
|
+ }
|
|
+ } else {
|
|
+ gpio_request_by_name(dev, "reset-gpios", 0,
|
|
+ &priv->rst_gpio, GPIOD_IS_OUT);
|
|
+ }
|
|
+ } else {
|
|
+ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0,
|
|
+ 0, &args);
|
|
+ if (ret) {
|
|
+ printf("error: phy-handle is not specified\n");
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ priv->phy_addr = ofnode_read_s32_default(args.node, "reg", -1);
|
|
+ if (priv->phy_addr < 0) {
|
|
+ printf("error: phy address is not specified\n");
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct mtk_soc_data mt7988_data = {
|
|
+ .caps = MT7988_CAPS,
|
|
+ .ana_rgc3 = 0x128,
|
|
+ .gdma_count = 3,
|
|
+ .pdma_base = PDMA_V3_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma_v2),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma_v2),
|
|
+};
|
|
+
|
|
+static const struct mtk_soc_data mt7986_data = {
|
|
+ .caps = MT7986_CAPS,
|
|
+ .ana_rgc3 = 0x128,
|
|
+ .gdma_count = 2,
|
|
+ .pdma_base = PDMA_V2_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma_v2),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma_v2),
|
|
+};
|
|
+
|
|
+static const struct mtk_soc_data mt7981_data = {
|
|
+ .caps = MT7981_CAPS,
|
|
+ .ana_rgc3 = 0x128,
|
|
+ .gdma_count = 2,
|
|
+ .pdma_base = PDMA_V2_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma_v2),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma_v2),
|
|
+};
|
|
+
|
|
+static const struct mtk_soc_data mt7629_data = {
|
|
+ .caps = MT7629_CAPS,
|
|
+ .ana_rgc3 = 0x128,
|
|
+ .gdma_count = 2,
|
|
+ .pdma_base = PDMA_V1_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma),
|
|
+};
|
|
+
|
|
+static const struct mtk_soc_data mt7623_data = {
|
|
+ .caps = MT7623_CAPS,
|
|
+ .gdma_count = 2,
|
|
+ .pdma_base = PDMA_V1_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma),
|
|
+};
|
|
+
|
|
+static const struct mtk_soc_data mt7622_data = {
|
|
+ .caps = MT7622_CAPS,
|
|
+ .ana_rgc3 = 0x2028,
|
|
+ .gdma_count = 2,
|
|
+ .pdma_base = PDMA_V1_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma),
|
|
+};
|
|
+
|
|
+static const struct mtk_soc_data mt7621_data = {
|
|
+ .caps = MT7621_CAPS,
|
|
+ .gdma_count = 2,
|
|
+ .pdma_base = PDMA_V1_BASE,
|
|
+ .txd_size = sizeof(struct mtk_tx_dma),
|
|
+ .rxd_size = sizeof(struct mtk_rx_dma),
|
|
+};
|
|
+
|
|
+static const struct udevice_id mtk_eth_ids[] = {
|
|
+ { .compatible = "mediatek,mt7988-eth", .data = (ulong)&mt7988_data },
|
|
+ { .compatible = "mediatek,mt7986-eth", .data = (ulong)&mt7986_data },
|
|
+ { .compatible = "mediatek,mt7981-eth", .data = (ulong)&mt7981_data },
|
|
+ { .compatible = "mediatek,mt7629-eth", .data = (ulong)&mt7629_data },
|
|
+ { .compatible = "mediatek,mt7623-eth", .data = (ulong)&mt7623_data },
|
|
+ { .compatible = "mediatek,mt7622-eth", .data = (ulong)&mt7622_data },
|
|
+ { .compatible = "mediatek,mt7621-eth", .data = (ulong)&mt7621_data },
|
|
+ {}
|
|
+};
|
|
+
|
|
+static const struct eth_ops mtk_eth_ops = {
|
|
+ .start = mtk_eth_start,
|
|
+ .stop = mtk_eth_stop,
|
|
+ .send = mtk_eth_send,
|
|
+ .recv = mtk_eth_recv,
|
|
+ .free_pkt = mtk_eth_free_pkt,
|
|
+ .write_hwaddr = mtk_eth_write_hwaddr,
|
|
+};
|
|
+
|
|
+U_BOOT_DRIVER(mtk_eth) = {
|
|
+ .name = "mtk-eth",
|
|
+ .id = UCLASS_ETH,
|
|
+ .of_match = mtk_eth_ids,
|
|
+ .of_to_plat = mtk_eth_of_to_plat,
|
|
+ .plat_auto = sizeof(struct eth_pdata),
|
|
+ .probe = mtk_eth_probe,
|
|
+ .remove = mtk_eth_remove,
|
|
+ .ops = &mtk_eth_ops,
|
|
+ .priv_auto = sizeof(struct mtk_eth_priv),
|
|
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
|
|
+};
|
|
--- a/drivers/net/mtk_eth.h
|
|
+++ /dev/null
|
|
@@ -1,600 +0,0 @@
|
|
-/* SPDX-License-Identifier: GPL-2.0 */
|
|
-/*
|
|
- * Copyright (C) 2018 MediaTek Inc.
|
|
- *
|
|
- * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
- * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
- */
|
|
-
|
|
-#ifndef _MTK_ETH_H_
|
|
-#define _MTK_ETH_H_
|
|
-
|
|
-#include <linux/bitops.h>
|
|
-#include <linux/bitfield.h>
|
|
-
|
|
-enum mkt_eth_capabilities {
|
|
- MTK_TRGMII_BIT,
|
|
- MTK_TRGMII_MT7621_CLK_BIT,
|
|
- MTK_U3_COPHY_V2_BIT,
|
|
- MTK_INFRA_BIT,
|
|
- MTK_NETSYS_V2_BIT,
|
|
- MTK_NETSYS_V3_BIT,
|
|
-
|
|
- /* PATH BITS */
|
|
- MTK_ETH_PATH_GMAC1_TRGMII_BIT,
|
|
- MTK_ETH_PATH_GMAC2_SGMII_BIT,
|
|
- MTK_ETH_PATH_MT7622_SGMII_BIT,
|
|
- MTK_ETH_PATH_MT7629_GMAC2_BIT,
|
|
-};
|
|
-
|
|
-#define MTK_TRGMII BIT(MTK_TRGMII_BIT)
|
|
-#define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT)
|
|
-#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT)
|
|
-#define MTK_INFRA BIT(MTK_INFRA_BIT)
|
|
-#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT)
|
|
-#define MTK_NETSYS_V3 BIT(MTK_NETSYS_V3_BIT)
|
|
-
|
|
-/* Supported path present on SoCs */
|
|
-#define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
|
|
-
|
|
-#define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
|
|
-#define MTK_ETH_PATH_MT7622_SGMII BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
|
|
-#define MTK_ETH_PATH_MT7629_GMAC2 BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
|
|
-
|
|
-#define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
|
|
-
|
|
-#define MTK_GMAC2_U3_QPHY (MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA)
|
|
-
|
|
-#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x))
|
|
-
|
|
-#define MT7621_CAPS (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
|
|
-
|
|
-#define MT7622_CAPS (MTK_ETH_PATH_MT7622_SGMII)
|
|
-
|
|
-#define MT7623_CAPS (MTK_GMAC1_TRGMII)
|
|
-
|
|
-#define MT7629_CAPS (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
|
|
-
|
|
-#define MT7981_CAPS (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
|
|
-
|
|
-#define MT7986_CAPS (MTK_NETSYS_V2)
|
|
-
|
|
-#define MT7988_CAPS (MTK_NETSYS_V3 | MTK_INFRA)
|
|
-
|
|
-/* Frame Engine Register Bases */
|
|
-#define PDMA_V1_BASE 0x0800
|
|
-#define PDMA_V2_BASE 0x6000
|
|
-#define PDMA_V3_BASE 0x6800
|
|
-#define GDMA1_BASE 0x0500
|
|
-#define GDMA2_BASE 0x1500
|
|
-#define GDMA3_BASE 0x0540
|
|
-#define GMAC_BASE 0x10000
|
|
-#define GSW_BASE 0x20000
|
|
-
|
|
-/* Ethernet subsystem registers */
|
|
-
|
|
-#define ETHSYS_SYSCFG1_REG 0x14
|
|
-#define SYSCFG1_GE_MODE_S(n) (12 + ((n) * 2))
|
|
-#define SYSCFG1_GE_MODE_M 0x3
|
|
-#define SYSCFG1_SGMII_SEL_M GENMASK(9, 8)
|
|
-#define SYSCFG1_SGMII_SEL(gmac) BIT(9 - (gmac))
|
|
-
|
|
-#define ETHSYS_CLKCFG0_REG 0x2c
|
|
-#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
|
|
-
|
|
-/* Top misc registers */
|
|
-#define TOPMISC_NETSYS_PCS_MUX 0x84
|
|
-#define NETSYS_PCS_MUX_MASK GENMASK(1, 0)
|
|
-#define MUX_G2_USXGMII_SEL BIT(1)
|
|
-#define MUX_HSGMII1_G1_SEL BIT(0)
|
|
-
|
|
-#define USB_PHY_SWITCH_REG 0x218
|
|
-#define QPHY_SEL_MASK 0x3
|
|
-#define SGMII_QPHY_SEL 0x2
|
|
-
|
|
-#define MT7629_INFRA_MISC2_REG 0x70c
|
|
-#define INFRA_MISC2_BONDING_OPTION GENMASK(15, 0)
|
|
-
|
|
-/* SYSCFG1_GE_MODE: GE Modes */
|
|
-#define GE_MODE_RGMII 0
|
|
-#define GE_MODE_MII 1
|
|
-#define GE_MODE_MII_PHY 2
|
|
-#define GE_MODE_RMII 3
|
|
-
|
|
-/* SGMII subsystem config registers */
|
|
-#define SGMSYS_PCS_CONTROL_1 0x0
|
|
-#define SGMII_LINK_STATUS BIT(18)
|
|
-#define SGMII_AN_ENABLE BIT(12)
|
|
-#define SGMII_AN_RESTART BIT(9)
|
|
-
|
|
-#define SGMSYS_SGMII_MODE 0x20
|
|
-#define SGMII_AN_MODE 0x31120103
|
|
-#define SGMII_FORCE_MODE 0x31120019
|
|
-
|
|
-#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
|
|
-#define SGMII_PHYA_PWD BIT(4)
|
|
-
|
|
-#define SGMSYS_QPHY_WRAP_CTRL 0xec
|
|
-#define SGMII_PN_SWAP_TX_RX 0x03
|
|
-
|
|
-#define SGMSYS_GEN2_SPEED 0x2028
|
|
-#define SGMSYS_GEN2_SPEED_V2 0x128
|
|
-#define SGMSYS_SPEED_MASK GENMASK(3, 2)
|
|
-#define SGMSYS_SPEED_2500 1
|
|
-
|
|
-/* USXGMII subsystem config registers */
|
|
-/* Register to control USXGMII XFI PLL digital */
|
|
-#define XFI_PLL_DIG_GLB8 0x08
|
|
-#define RG_XFI_PLL_EN BIT(31)
|
|
-
|
|
-/* Register to control USXGMII XFI PLL analog */
|
|
-#define XFI_PLL_ANA_GLB8 0x108
|
|
-#define RG_XFI_PLL_ANA_SWWA 0x02283248
|
|
-
|
|
-/* Frame Engine Registers */
|
|
-#define PSE_NO_DROP_CFG_REG 0x108
|
|
-#define PSE_NO_DROP_GDM1 BIT(1)
|
|
-
|
|
-#define FE_GLO_MISC_REG 0x124
|
|
-#define PDMA_VER_V2 BIT(4)
|
|
-
|
|
-/* PDMA */
|
|
-#define TX_BASE_PTR_REG(n) (0x000 + (n) * 0x10)
|
|
-#define TX_MAX_CNT_REG(n) (0x004 + (n) * 0x10)
|
|
-#define TX_CTX_IDX_REG(n) (0x008 + (n) * 0x10)
|
|
-#define TX_DTX_IDX_REG(n) (0x00c + (n) * 0x10)
|
|
-
|
|
-#define RX_BASE_PTR_REG(n) (0x100 + (n) * 0x10)
|
|
-#define RX_MAX_CNT_REG(n) (0x104 + (n) * 0x10)
|
|
-#define RX_CRX_IDX_REG(n) (0x108 + (n) * 0x10)
|
|
-#define RX_DRX_IDX_REG(n) (0x10c + (n) * 0x10)
|
|
-
|
|
-#define PDMA_GLO_CFG_REG 0x204
|
|
-#define TX_WB_DDONE BIT(6)
|
|
-#define RX_DMA_BUSY BIT(3)
|
|
-#define RX_DMA_EN BIT(2)
|
|
-#define TX_DMA_BUSY BIT(1)
|
|
-#define TX_DMA_EN BIT(0)
|
|
-
|
|
-#define PDMA_RST_IDX_REG 0x208
|
|
-#define RST_DRX_IDX0 BIT(16)
|
|
-#define RST_DTX_IDX0 BIT(0)
|
|
-
|
|
-/* GDMA */
|
|
-#define GDMA_IG_CTRL_REG 0x000
|
|
-#define GDM_ICS_EN BIT(22)
|
|
-#define GDM_TCS_EN BIT(21)
|
|
-#define GDM_UCS_EN BIT(20)
|
|
-#define STRP_CRC BIT(16)
|
|
-#define MYMAC_DP_S 12
|
|
-#define MYMAC_DP_M 0xf000
|
|
-#define BC_DP_S 8
|
|
-#define BC_DP_M 0xf00
|
|
-#define MC_DP_S 4
|
|
-#define MC_DP_M 0xf0
|
|
-#define UN_DP_S 0
|
|
-#define UN_DP_M 0x0f
|
|
-
|
|
-#define GDMA_EG_CTRL_REG 0x004
|
|
-#define GDMA_CPU_BRIDGE_EN BIT(31)
|
|
-
|
|
-#define GDMA_MAC_LSB_REG 0x008
|
|
-
|
|
-#define GDMA_MAC_MSB_REG 0x00c
|
|
-
|
|
-/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */
|
|
-#define DP_PDMA 0
|
|
-#define DP_GDMA1 1
|
|
-#define DP_GDMA2 2
|
|
-#define DP_PPE 4
|
|
-#define DP_QDMA 5
|
|
-#define DP_DISCARD 7
|
|
-
|
|
-/* GMAC Registers */
|
|
-
|
|
-#define GMAC_PPSC_REG 0x0000
|
|
-#define PHY_MDC_CFG GENMASK(29, 24)
|
|
-#define MDC_TURBO BIT(20)
|
|
-#define MDC_MAX_FREQ 25000000
|
|
-#define MDC_MAX_DIVIDER 63
|
|
-
|
|
-#define GMAC_PIAC_REG 0x0004
|
|
-#define PHY_ACS_ST BIT(31)
|
|
-#define MDIO_REG_ADDR_S 25
|
|
-#define MDIO_REG_ADDR_M 0x3e000000
|
|
-#define MDIO_PHY_ADDR_S 20
|
|
-#define MDIO_PHY_ADDR_M 0x1f00000
|
|
-#define MDIO_CMD_S 18
|
|
-#define MDIO_CMD_M 0xc0000
|
|
-#define MDIO_ST_S 16
|
|
-#define MDIO_ST_M 0x30000
|
|
-#define MDIO_RW_DATA_S 0
|
|
-#define MDIO_RW_DATA_M 0xffff
|
|
-
|
|
-#define GMAC_XGMAC_STS_REG 0x000c
|
|
-#define P1_XGMAC_FORCE_LINK BIT(15)
|
|
-
|
|
-#define GMAC_MAC_MISC_REG 0x0010
|
|
-#define MISC_MDC_TURBO BIT(4)
|
|
-
|
|
-#define GMAC_GSW_CFG_REG 0x0080
|
|
-#define GSWTX_IPG_M 0xF0000
|
|
-#define GSWTX_IPG_S 16
|
|
-#define GSWRX_IPG_M 0xF
|
|
-#define GSWRX_IPG_S 0
|
|
-
|
|
-/* MDIO_CMD: MDIO commands */
|
|
-#define MDIO_CMD_ADDR 0
|
|
-#define MDIO_CMD_WRITE 1
|
|
-#define MDIO_CMD_READ 2
|
|
-#define MDIO_CMD_READ_C45 3
|
|
-
|
|
-/* MDIO_ST: MDIO start field */
|
|
-#define MDIO_ST_C45 0
|
|
-#define MDIO_ST_C22 1
|
|
-
|
|
-#define GMAC_PORT_MCR(p) (0x0100 + (p) * 0x100)
|
|
-#define MAC_RX_PKT_LEN_S 24
|
|
-#define MAC_RX_PKT_LEN_M 0x3000000
|
|
-#define IPG_CFG_S 18
|
|
-#define IPG_CFG_M 0xc0000
|
|
-#define MAC_MODE BIT(16)
|
|
-#define FORCE_MODE BIT(15)
|
|
-#define MAC_TX_EN BIT(14)
|
|
-#define MAC_RX_EN BIT(13)
|
|
-#define DEL_RXFIFO_CLR BIT(12)
|
|
-#define BKOFF_EN BIT(9)
|
|
-#define BACKPR_EN BIT(8)
|
|
-#define FORCE_RX_FC BIT(5)
|
|
-#define FORCE_TX_FC BIT(4)
|
|
-#define FORCE_SPD_S 2
|
|
-#define FORCE_SPD_M 0x0c
|
|
-#define FORCE_DPX BIT(1)
|
|
-#define FORCE_LINK BIT(0)
|
|
-
|
|
-/* Values of IPG_CFG */
|
|
-#define IPG_96BIT 0
|
|
-#define IPG_96BIT_WITH_SHORT_IPG 1
|
|
-#define IPG_64BIT 2
|
|
-
|
|
-/* MAC_RX_PKT_LEN: Max RX packet length */
|
|
-#define MAC_RX_PKT_LEN_1518 0
|
|
-#define MAC_RX_PKT_LEN_1536 1
|
|
-#define MAC_RX_PKT_LEN_1552 2
|
|
-#define MAC_RX_PKT_LEN_JUMBO 3
|
|
-
|
|
-/* FORCE_SPD: Forced link speed */
|
|
-#define SPEED_10M 0
|
|
-#define SPEED_100M 1
|
|
-#define SPEED_1000M 2
|
|
-
|
|
-#define GMAC_TRGMII_RCK_CTRL 0x300
|
|
-#define RX_RST BIT(31)
|
|
-#define RXC_DQSISEL BIT(30)
|
|
-
|
|
-#define GMAC_TRGMII_TD_ODT(n) (0x354 + (n) * 8)
|
|
-#define TD_DM_DRVN_S 4
|
|
-#define TD_DM_DRVN_M 0xf0
|
|
-#define TD_DM_DRVP_S 0
|
|
-#define TD_DM_DRVP_M 0x0f
|
|
-
|
|
-/* XGMAC Status Registers */
|
|
-#define XGMAC_STS(x) (((x) == 2) ? 0x001C : 0x000C)
|
|
-#define XGMAC_FORCE_LINK(x) (((x) == 1) ? BIT(31) : BIT(15))
|
|
-
|
|
-/* XGMAC Registers */
|
|
-#define XGMAC_PORT_MCR(x) (0x2000 + (((x) - 1) * 0x1000))
|
|
-#define XGMAC_TRX_DISABLE 0xf
|
|
-#define XGMAC_FORCE_TX_FC BIT(5)
|
|
-#define XGMAC_FORCE_RX_FC BIT(4)
|
|
-
|
|
-/* MT7530 Registers */
|
|
-
|
|
-#define PCR_REG(p) (0x2004 + (p) * 0x100)
|
|
-#define PORT_MATRIX_S 16
|
|
-#define PORT_MATRIX_M 0xff0000
|
|
-
|
|
-#define PVC_REG(p) (0x2010 + (p) * 0x100)
|
|
-#define STAG_VPID_S 16
|
|
-#define STAG_VPID_M 0xffff0000
|
|
-#define VLAN_ATTR_S 6
|
|
-#define VLAN_ATTR_M 0xc0
|
|
-
|
|
-/* VLAN_ATTR: VLAN attributes */
|
|
-#define VLAN_ATTR_USER 0
|
|
-#define VLAN_ATTR_STACK 1
|
|
-#define VLAN_ATTR_TRANSLATION 2
|
|
-#define VLAN_ATTR_TRANSPARENT 3
|
|
-
|
|
-#define PMCR_REG(p) (0x3000 + (p) * 0x100)
|
|
-/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
|
|
- * MT7531 specific fields are defined below
|
|
- */
|
|
-#define FORCE_MODE_EEE1G BIT(25)
|
|
-#define FORCE_MODE_EEE100 BIT(26)
|
|
-#define FORCE_MODE_TX_FC BIT(27)
|
|
-#define FORCE_MODE_RX_FC BIT(28)
|
|
-#define FORCE_MODE_DPX BIT(29)
|
|
-#define FORCE_MODE_SPD BIT(30)
|
|
-#define FORCE_MODE_LNK BIT(31)
|
|
-#define MT7531_FORCE_MODE FORCE_MODE_EEE1G | FORCE_MODE_EEE100 |\
|
|
- FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
|
|
- FORCE_MODE_DPX | FORCE_MODE_SPD | \
|
|
- FORCE_MODE_LNK
|
|
-#define MT7988_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
|
|
- FORCE_MODE_DPX | FORCE_MODE_SPD | \
|
|
- FORCE_MODE_LNK
|
|
-
|
|
-/* MT7531 SGMII Registers */
|
|
-#define MT7531_SGMII_REG_BASE 0x5000
|
|
-#define MT7531_SGMII_REG_PORT_BASE 0x1000
|
|
-#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \
|
|
- (p) * MT7531_SGMII_REG_PORT_BASE + (r))
|
|
-#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(((p) - 5), 0x00)
|
|
-#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(((p) - 5), 0x20)
|
|
-#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8)
|
|
-#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(((p) - 5), 0x128)
|
|
-/* XXX: all fields of MT7531 SGMII are defined under SGMSYS */
|
|
-
|
|
-/* MT753x System Control Register */
|
|
-#define SYS_CTRL_REG 0x7000
|
|
-#define SW_PHY_RST BIT(2)
|
|
-#define SW_SYS_RST BIT(1)
|
|
-#define SW_REG_RST BIT(0)
|
|
-
|
|
-/* MT7531 */
|
|
-#define MT7531_PHY_IAC 0x701c
|
|
-/* XXX: all fields are defined under GMAC_PIAC_REG */
|
|
-
|
|
-#define MT7531_CLKGEN_CTRL 0x7500
|
|
-#define CLK_SKEW_OUT_S 8
|
|
-#define CLK_SKEW_OUT_M 0x300
|
|
-#define CLK_SKEW_IN_S 6
|
|
-#define CLK_SKEW_IN_M 0xc0
|
|
-#define RXCLK_NO_DELAY BIT(5)
|
|
-#define TXCLK_NO_REVERSE BIT(4)
|
|
-#define GP_MODE_S 1
|
|
-#define GP_MODE_M 0x06
|
|
-#define GP_CLK_EN BIT(0)
|
|
-
|
|
-/* Values of GP_MODE */
|
|
-#define GP_MODE_RGMII 0
|
|
-#define GP_MODE_MII 1
|
|
-#define GP_MODE_REV_MII 2
|
|
-
|
|
-/* Values of CLK_SKEW_IN */
|
|
-#define CLK_SKEW_IN_NO_CHANGE 0
|
|
-#define CLK_SKEW_IN_DELAY_100PPS 1
|
|
-#define CLK_SKEW_IN_DELAY_200PPS 2
|
|
-#define CLK_SKEW_IN_REVERSE 3
|
|
-
|
|
-/* Values of CLK_SKEW_OUT */
|
|
-#define CLK_SKEW_OUT_NO_CHANGE 0
|
|
-#define CLK_SKEW_OUT_DELAY_100PPS 1
|
|
-#define CLK_SKEW_OUT_DELAY_200PPS 2
|
|
-#define CLK_SKEW_OUT_REVERSE 3
|
|
-
|
|
-#define HWTRAP_REG 0x7800
|
|
-/* MT7530 Modified Hardware Trap Status Registers */
|
|
-#define MHWTRAP_REG 0x7804
|
|
-#define CHG_TRAP BIT(16)
|
|
-#define LOOPDET_DIS BIT(14)
|
|
-#define P5_INTF_SEL_S 13
|
|
-#define P5_INTF_SEL_M 0x2000
|
|
-#define SMI_ADDR_S 11
|
|
-#define SMI_ADDR_M 0x1800
|
|
-#define XTAL_FSEL_S 9
|
|
-#define XTAL_FSEL_M 0x600
|
|
-#define P6_INTF_DIS BIT(8)
|
|
-#define P5_INTF_MODE_S 7
|
|
-#define P5_INTF_MODE_M 0x80
|
|
-#define P5_INTF_DIS BIT(6)
|
|
-#define C_MDIO_BPS BIT(5)
|
|
-#define CHIP_MODE_S 0
|
|
-#define CHIP_MODE_M 0x0f
|
|
-
|
|
-/* P5_INTF_SEL: Interface type of Port5 */
|
|
-#define P5_INTF_SEL_GPHY 0
|
|
-#define P5_INTF_SEL_GMAC5 1
|
|
-
|
|
-/* P5_INTF_MODE: Interface mode of Port5 */
|
|
-#define P5_INTF_MODE_GMII_MII 0
|
|
-#define P5_INTF_MODE_RGMII 1
|
|
-
|
|
-#define MT7530_P6ECR 0x7830
|
|
-#define P6_INTF_MODE_M 0x3
|
|
-#define P6_INTF_MODE_S 0
|
|
-
|
|
-/* P6_INTF_MODE: Interface mode of Port6 */
|
|
-#define P6_INTF_MODE_RGMII 0
|
|
-#define P6_INTF_MODE_TRGMII 1
|
|
-
|
|
-#define NUM_TRGMII_CTRL 5
|
|
-
|
|
-#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8)
|
|
-#define RD_TAP_S 0
|
|
-#define RD_TAP_M 0x7f
|
|
-
|
|
-#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8)
|
|
-/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
|
|
-
|
|
-/* TOP Signals Status Register */
|
|
-#define MT7531_TOP_SIG_SR 0x780c
|
|
-#define PAD_MCM_SMI_EN BIT(0)
|
|
-#define PAD_DUAL_SGMII_EN BIT(1)
|
|
-
|
|
-/* MT7531 PLLGP Registers */
|
|
-#define MT7531_PLLGP_EN 0x7820
|
|
-#define EN_COREPLL BIT(2)
|
|
-#define SW_CLKSW BIT(1)
|
|
-#define SW_PLLGP BIT(0)
|
|
-
|
|
-#define MT7531_PLLGP_CR0 0x78a8
|
|
-#define RG_COREPLL_EN BIT(22)
|
|
-#define RG_COREPLL_POSDIV_S 23
|
|
-#define RG_COREPLL_POSDIV_M 0x3800000
|
|
-#define RG_COREPLL_SDM_PCW_S 1
|
|
-#define RG_COREPLL_SDM_PCW_M 0x3ffffe
|
|
-#define RG_COREPLL_SDM_PCW_CHG BIT(0)
|
|
-
|
|
-/* MT7531 RGMII and SGMII PLL clock */
|
|
-#define MT7531_ANA_PLLGP_CR2 0x78b0
|
|
-#define MT7531_ANA_PLLGP_CR5 0x78bc
|
|
-
|
|
-/* MT7531 GPIO GROUP IOLB SMT0 Control */
|
|
-#define MT7531_SMT0_IOLB 0x7f04
|
|
-#define SMT_IOLB_5_SMI_MDC_EN BIT(5)
|
|
-
|
|
-/* MT7530 GPHY MDIO Indirect Access Registers */
|
|
-#define MII_MMD_ACC_CTL_REG 0x0d
|
|
-#define MMD_CMD_S 14
|
|
-#define MMD_CMD_M 0xc000
|
|
-#define MMD_DEVAD_S 0
|
|
-#define MMD_DEVAD_M 0x1f
|
|
-
|
|
-/* MMD_CMD: MMD commands */
|
|
-#define MMD_ADDR 0
|
|
-#define MMD_DATA 1
|
|
-#define MMD_DATA_RW_POST_INC 2
|
|
-#define MMD_DATA_W_POST_INC 3
|
|
-
|
|
-#define MII_MMD_ADDR_DATA_REG 0x0e
|
|
-
|
|
-/* MT7530 GPHY MDIO MMD Registers */
|
|
-#define CORE_PLL_GROUP2 0x401
|
|
-#define RG_SYSPLL_EN_NORMAL BIT(15)
|
|
-#define RG_SYSPLL_VODEN BIT(14)
|
|
-#define RG_SYSPLL_POSDIV_S 5
|
|
-#define RG_SYSPLL_POSDIV_M 0x60
|
|
-
|
|
-#define CORE_PLL_GROUP4 0x403
|
|
-#define MT7531_BYPASS_MODE BIT(4)
|
|
-#define MT7531_POWER_ON_OFF BIT(5)
|
|
-#define RG_SYSPLL_DDSFBK_EN BIT(12)
|
|
-#define RG_SYSPLL_BIAS_EN BIT(11)
|
|
-#define RG_SYSPLL_BIAS_LPF_EN BIT(10)
|
|
-
|
|
-#define CORE_PLL_GROUP5 0x404
|
|
-#define RG_LCDDS_PCW_NCPO1_S 0
|
|
-#define RG_LCDDS_PCW_NCPO1_M 0xffff
|
|
-
|
|
-#define CORE_PLL_GROUP6 0x405
|
|
-#define RG_LCDDS_PCW_NCPO0_S 0
|
|
-#define RG_LCDDS_PCW_NCPO0_M 0xffff
|
|
-
|
|
-#define CORE_PLL_GROUP7 0x406
|
|
-#define RG_LCDDS_PWDB BIT(15)
|
|
-#define RG_LCDDS_ISO_EN BIT(13)
|
|
-#define RG_LCCDS_C_S 4
|
|
-#define RG_LCCDS_C_M 0x70
|
|
-#define RG_LCDDS_PCW_NCPO_CHG BIT(3)
|
|
-
|
|
-#define CORE_PLL_GROUP10 0x409
|
|
-#define RG_LCDDS_SSC_DELTA_S 0
|
|
-#define RG_LCDDS_SSC_DELTA_M 0xfff
|
|
-
|
|
-#define CORE_PLL_GROUP11 0x40a
|
|
-#define RG_LCDDS_SSC_DELTA1_S 0
|
|
-#define RG_LCDDS_SSC_DELTA1_M 0xfff
|
|
-
|
|
-#define CORE_GSWPLL_GRP1 0x40d
|
|
-#define RG_GSWPLL_POSDIV_200M_S 12
|
|
-#define RG_GSWPLL_POSDIV_200M_M 0x3000
|
|
-#define RG_GSWPLL_EN_PRE BIT(11)
|
|
-#define RG_GSWPLL_FBKDIV_200M_S 0
|
|
-#define RG_GSWPLL_FBKDIV_200M_M 0xff
|
|
-
|
|
-#define CORE_GSWPLL_GRP2 0x40e
|
|
-#define RG_GSWPLL_POSDIV_500M_S 8
|
|
-#define RG_GSWPLL_POSDIV_500M_M 0x300
|
|
-#define RG_GSWPLL_FBKDIV_500M_S 0
|
|
-#define RG_GSWPLL_FBKDIV_500M_M 0xff
|
|
-
|
|
-#define CORE_TRGMII_GSW_CLK_CG 0x410
|
|
-#define REG_GSWCK_EN BIT(0)
|
|
-#define REG_TRGMIICK_EN BIT(1)
|
|
-
|
|
-/* Extend PHY Control Register 3 */
|
|
-#define PHY_EXT_REG_14 0x14
|
|
-
|
|
-/* Fields of PHY_EXT_REG_14 */
|
|
-#define PHY_EN_DOWN_SHFIT BIT(4)
|
|
-
|
|
-/* Extend PHY Control Register 4 */
|
|
-#define PHY_EXT_REG_17 0x17
|
|
-
|
|
-/* Fields of PHY_EXT_REG_17 */
|
|
-#define PHY_LINKDOWN_POWER_SAVING_EN BIT(4)
|
|
-
|
|
-/* PHY RXADC Control Register 7 */
|
|
-#define PHY_DEV1E_REG_0C6 0x0c6
|
|
-
|
|
-/* Fields of PHY_DEV1E_REG_0C6 */
|
|
-#define PHY_POWER_SAVING_S 8
|
|
-#define PHY_POWER_SAVING_M 0x300
|
|
-#define PHY_POWER_SAVING_TX 0x0
|
|
-
|
|
-/* PDMA descriptors */
|
|
-struct mtk_rx_dma {
|
|
- unsigned int rxd1;
|
|
- unsigned int rxd2;
|
|
- unsigned int rxd3;
|
|
- unsigned int rxd4;
|
|
-} __packed __aligned(4);
|
|
-
|
|
-struct mtk_rx_dma_v2 {
|
|
- unsigned int rxd1;
|
|
- unsigned int rxd2;
|
|
- unsigned int rxd3;
|
|
- unsigned int rxd4;
|
|
- unsigned int rxd5;
|
|
- unsigned int rxd6;
|
|
- unsigned int rxd7;
|
|
- unsigned int rxd8;
|
|
-} __packed __aligned(4);
|
|
-
|
|
-struct mtk_tx_dma {
|
|
- unsigned int txd1;
|
|
- unsigned int txd2;
|
|
- unsigned int txd3;
|
|
- unsigned int txd4;
|
|
-} __packed __aligned(4);
|
|
-
|
|
-struct mtk_tx_dma_v2 {
|
|
- unsigned int txd1;
|
|
- unsigned int txd2;
|
|
- unsigned int txd3;
|
|
- unsigned int txd4;
|
|
- unsigned int txd5;
|
|
- unsigned int txd6;
|
|
- unsigned int txd7;
|
|
- unsigned int txd8;
|
|
-} __packed __aligned(4);
|
|
-
|
|
-/* PDMA TXD fields */
|
|
-#define PDMA_TXD2_DDONE BIT(31)
|
|
-#define PDMA_TXD2_LS0 BIT(30)
|
|
-#define PDMA_V1_TXD2_SDL0_M GENMASK(29, 16)
|
|
-#define PDMA_V1_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
|
|
-#define PDMA_V2_TXD2_SDL0_M GENMASK(23, 8)
|
|
-#define PDMA_V2_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
|
|
-
|
|
-#define PDMA_V1_TXD4_FPORT_M GENMASK(27, 25)
|
|
-#define PDMA_V1_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
|
|
-#define PDMA_V2_TXD4_FPORT_M GENMASK(27, 24)
|
|
-#define PDMA_V2_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
|
|
-
|
|
-#define PDMA_V2_TXD5_FPORT_M GENMASK(19, 16)
|
|
-#define PDMA_V2_TXD5_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
|
|
-
|
|
-/* PDMA RXD fields */
|
|
-#define PDMA_RXD2_DDONE BIT(31)
|
|
-#define PDMA_RXD2_LS0 BIT(30)
|
|
-#define PDMA_V1_RXD2_PLEN0_M GENMASK(29, 16)
|
|
-#define PDMA_V1_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
|
|
-#define PDMA_V1_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
|
|
-#define PDMA_V2_RXD2_PLEN0_M GENMASK(23, 8)
|
|
-#define PDMA_V2_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
|
|
-#define PDMA_V2_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
|
|
-
|
|
-#endif /* _MTK_ETH_H_ */
|
|
--- /dev/null
|
|
+++ b/drivers/net/mtk_eth/mtk_eth.h
|
|
@@ -0,0 +1,429 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0 */
|
|
+/*
|
|
+ * Copyright (C) 2025 MediaTek Inc.
|
|
+ *
|
|
+ * Author: Weijie Gao <weijie.gao@mediatek.com>
|
|
+ * Author: Mark Lee <mark-mc.lee@mediatek.com>
|
|
+ */
|
|
+
|
|
+#ifndef _MTK_ETH_H_
|
|
+#define _MTK_ETH_H_
|
|
+
|
|
+#include <linker_lists.h>
|
|
+#include <linux/bitops.h>
|
|
+#include <linux/bitfield.h>
|
|
+
|
|
+struct mtk_eth_priv;
|
|
+struct mtk_eth_switch_priv;
|
|
+
|
|
+/* struct mtk_soc_data - This is the structure holding all differences
|
|
+ * among various plaforms
|
|
+ * @caps Flags shown the extra capability for the SoC
|
|
+ * @ana_rgc3: The offset for register ANA_RGC3 related to
|
|
+ * sgmiisys syscon
|
|
+ * @gdma_count: Number of GDMAs
|
|
+ * @pdma_base: Register base of PDMA block
|
|
+ * @txd_size: Tx DMA descriptor size.
|
|
+ * @rxd_size: Rx DMA descriptor size.
|
|
+ */
|
|
+struct mtk_soc_data {
|
|
+ u32 caps;
|
|
+ u32 ana_rgc3;
|
|
+ u32 gdma_count;
|
|
+ u32 pdma_base;
|
|
+ u32 txd_size;
|
|
+ u32 rxd_size;
|
|
+};
|
|
+
|
|
+struct mtk_eth_switch {
|
|
+ const char *name;
|
|
+ const char *desc;
|
|
+ size_t priv_size;
|
|
+ u32 reset_wait_time;
|
|
+
|
|
+ int (*detect)(struct mtk_eth_priv *priv);
|
|
+ int (*setup)(struct mtk_eth_switch_priv *priv);
|
|
+ int (*cleanup)(struct mtk_eth_switch_priv *priv);
|
|
+ void (*mac_control)(struct mtk_eth_switch_priv *priv, bool enable);
|
|
+};
|
|
+
|
|
+#define MTK_ETH_SWITCH(__name) \
|
|
+ ll_entry_declare(struct mtk_eth_switch, __name, mtk_eth_switch)
|
|
+
|
|
+struct mtk_eth_switch_priv {
|
|
+ struct mtk_eth_priv *eth;
|
|
+ const struct mtk_eth_switch *sw;
|
|
+ const struct mtk_soc_data *soc;
|
|
+ void *ethsys_base;
|
|
+ int phy_interface;
|
|
+};
|
|
+
|
|
+enum mkt_eth_capabilities {
|
|
+ MTK_TRGMII_BIT,
|
|
+ MTK_TRGMII_MT7621_CLK_BIT,
|
|
+ MTK_U3_COPHY_V2_BIT,
|
|
+ MTK_INFRA_BIT,
|
|
+ MTK_NETSYS_V2_BIT,
|
|
+ MTK_NETSYS_V3_BIT,
|
|
+
|
|
+ /* PATH BITS */
|
|
+ MTK_ETH_PATH_GMAC1_TRGMII_BIT,
|
|
+ MTK_ETH_PATH_GMAC2_SGMII_BIT,
|
|
+ MTK_ETH_PATH_MT7622_SGMII_BIT,
|
|
+ MTK_ETH_PATH_MT7629_GMAC2_BIT,
|
|
+};
|
|
+
|
|
+#define MTK_TRGMII BIT(MTK_TRGMII_BIT)
|
|
+#define MTK_TRGMII_MT7621_CLK BIT(MTK_TRGMII_MT7621_CLK_BIT)
|
|
+#define MTK_U3_COPHY_V2 BIT(MTK_U3_COPHY_V2_BIT)
|
|
+#define MTK_INFRA BIT(MTK_INFRA_BIT)
|
|
+#define MTK_NETSYS_V2 BIT(MTK_NETSYS_V2_BIT)
|
|
+#define MTK_NETSYS_V3 BIT(MTK_NETSYS_V3_BIT)
|
|
+
|
|
+/* Supported path present on SoCs */
|
|
+#define MTK_ETH_PATH_GMAC1_TRGMII BIT(MTK_ETH_PATH_GMAC1_TRGMII_BIT)
|
|
+#define MTK_ETH_PATH_GMAC2_SGMII BIT(MTK_ETH_PATH_GMAC2_SGMII_BIT)
|
|
+#define MTK_ETH_PATH_MT7622_SGMII BIT(MTK_ETH_PATH_MT7622_SGMII_BIT)
|
|
+#define MTK_ETH_PATH_MT7629_GMAC2 BIT(MTK_ETH_PATH_MT7629_GMAC2_BIT)
|
|
+
|
|
+#define MTK_GMAC1_TRGMII (MTK_ETH_PATH_GMAC1_TRGMII | MTK_TRGMII)
|
|
+
|
|
+#define MTK_GMAC2_U3_QPHY (MTK_ETH_PATH_GMAC2_SGMII | MTK_U3_COPHY_V2 | MTK_INFRA)
|
|
+
|
|
+#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x))
|
|
+
|
|
+#define MT7621_CAPS (MTK_GMAC1_TRGMII | MTK_TRGMII_MT7621_CLK)
|
|
+
|
|
+#define MT7622_CAPS (MTK_ETH_PATH_MT7622_SGMII)
|
|
+
|
|
+#define MT7623_CAPS (MTK_GMAC1_TRGMII)
|
|
+
|
|
+#define MT7629_CAPS (MTK_ETH_PATH_MT7629_GMAC2 | MTK_INFRA)
|
|
+
|
|
+#define MT7981_CAPS (MTK_GMAC2_U3_QPHY | MTK_NETSYS_V2)
|
|
+
|
|
+#define MT7986_CAPS (MTK_NETSYS_V2)
|
|
+
|
|
+#define MT7987_CAPS (MTK_NETSYS_V3 | MTK_GMAC2_U3_QPHY | MTK_INFRA)
|
|
+
|
|
+#define MT7988_CAPS (MTK_NETSYS_V3 | MTK_INFRA)
|
|
+
|
|
+/* Frame Engine Register Bases */
|
|
+#define PDMA_V1_BASE 0x0800
|
|
+#define PDMA_V2_BASE 0x6000
|
|
+#define PDMA_V3_BASE 0x6800
|
|
+#define GDMA1_BASE 0x0500
|
|
+#define GDMA2_BASE 0x1500
|
|
+#define GDMA3_BASE 0x0540
|
|
+#define GMAC_BASE 0x10000
|
|
+#define GSW_BASE 0x20000
|
|
+
|
|
+/* Ethernet subsystem registers */
|
|
+#define ETHSYS_SYSCFG1_REG 0x14
|
|
+#define SYSCFG1_GE_MODE_S(n) (12 + ((n) * 2))
|
|
+#define SYSCFG1_GE_MODE_M 0x3
|
|
+#define SYSCFG1_SGMII_SEL_M GENMASK(9, 8)
|
|
+#define SYSCFG1_SGMII_SEL(gmac) BIT(9 - (gmac))
|
|
+
|
|
+#define ETHSYS_CLKCFG0_REG 0x2c
|
|
+#define ETHSYS_TRGMII_CLK_SEL362_5 BIT(11)
|
|
+
|
|
+/* Top misc registers */
|
|
+#define TOPMISC_NETSYS_PCS_MUX 0x84
|
|
+#define NETSYS_PCS_MUX_MASK GENMASK(1, 0)
|
|
+#define MUX_G2_USXGMII_SEL BIT(1)
|
|
+#define MUX_HSGMII1_G1_SEL BIT(0)
|
|
+
|
|
+#define USB_PHY_SWITCH_REG 0x218
|
|
+#define QPHY_SEL_MASK 0x3
|
|
+#define SGMII_QPHY_SEL 0x2
|
|
+
|
|
+#define MT7629_INFRA_MISC2_REG 0x70c
|
|
+#define INFRA_MISC2_BONDING_OPTION GENMASK(15, 0)
|
|
+
|
|
+/* SYSCFG1_GE_MODE: GE Modes */
|
|
+#define GE_MODE_RGMII 0
|
|
+#define GE_MODE_MII 1
|
|
+#define GE_MODE_MII_PHY 2
|
|
+#define GE_MODE_RMII 3
|
|
+
|
|
+/* SGMII subsystem config registers */
|
|
+#define SGMSYS_PCS_CONTROL_1 0x0
|
|
+#define SGMII_LINK_STATUS BIT(18)
|
|
+#define SGMII_AN_ENABLE BIT(12)
|
|
+#define SGMII_AN_RESTART BIT(9)
|
|
+
|
|
+#define SGMSYS_SGMII_MODE 0x20
|
|
+#define SGMII_AN_MODE 0x31120103
|
|
+#define SGMII_FORCE_MODE 0x31120019
|
|
+
|
|
+#define SGMSYS_QPHY_PWR_STATE_CTRL 0xe8
|
|
+#define SGMII_PHYA_PWD BIT(4)
|
|
+
|
|
+#define SGMSYS_QPHY_WRAP_CTRL 0xec
|
|
+#define SGMII_PN_SWAP_TX_RX 0x03
|
|
+
|
|
+#define SGMSYS_GEN2_SPEED 0x2028
|
|
+#define SGMSYS_GEN2_SPEED_V2 0x128
|
|
+#define SGMSYS_SPEED_MASK GENMASK(3, 2)
|
|
+#define SGMSYS_SPEED_2500 1
|
|
+
|
|
+/* USXGMII subsystem config registers */
|
|
+/* Register to control USXGMII XFI PLL digital */
|
|
+#define XFI_PLL_DIG_GLB8 0x08
|
|
+#define RG_XFI_PLL_EN BIT(31)
|
|
+
|
|
+/* Register to control USXGMII XFI PLL analog */
|
|
+#define XFI_PLL_ANA_GLB8 0x108
|
|
+#define RG_XFI_PLL_ANA_SWWA 0x02283248
|
|
+
|
|
+/* Frame Engine Registers */
|
|
+#define PSE_NO_DROP_CFG_REG 0x108
|
|
+#define PSE_NO_DROP_GDM1 BIT(1)
|
|
+
|
|
+#define FE_GLO_MISC_REG 0x124
|
|
+#define PDMA_VER_V2 BIT(4)
|
|
+
|
|
+/* PDMA */
|
|
+#define TX_BASE_PTR_REG(n) (0x000 + (n) * 0x10)
|
|
+#define TX_MAX_CNT_REG(n) (0x004 + (n) * 0x10)
|
|
+#define TX_CTX_IDX_REG(n) (0x008 + (n) * 0x10)
|
|
+#define TX_DTX_IDX_REG(n) (0x00c + (n) * 0x10)
|
|
+
|
|
+#define RX_BASE_PTR_REG(n) (0x100 + (n) * 0x10)
|
|
+#define RX_MAX_CNT_REG(n) (0x104 + (n) * 0x10)
|
|
+#define RX_CRX_IDX_REG(n) (0x108 + (n) * 0x10)
|
|
+#define RX_DRX_IDX_REG(n) (0x10c + (n) * 0x10)
|
|
+
|
|
+#define PDMA_GLO_CFG_REG 0x204
|
|
+#define TX_WB_DDONE BIT(6)
|
|
+#define RX_DMA_BUSY BIT(3)
|
|
+#define RX_DMA_EN BIT(2)
|
|
+#define TX_DMA_BUSY BIT(1)
|
|
+#define TX_DMA_EN BIT(0)
|
|
+
|
|
+#define PDMA_RST_IDX_REG 0x208
|
|
+#define RST_DRX_IDX0 BIT(16)
|
|
+#define RST_DTX_IDX0 BIT(0)
|
|
+
|
|
+/* GDMA */
|
|
+#define GDMA_IG_CTRL_REG 0x000
|
|
+#define GDM_ICS_EN BIT(22)
|
|
+#define GDM_TCS_EN BIT(21)
|
|
+#define GDM_UCS_EN BIT(20)
|
|
+#define STRP_CRC BIT(16)
|
|
+#define MYMAC_DP_S 12
|
|
+#define MYMAC_DP_M 0xf000
|
|
+#define BC_DP_S 8
|
|
+#define BC_DP_M 0xf00
|
|
+#define MC_DP_S 4
|
|
+#define MC_DP_M 0xf0
|
|
+#define UN_DP_S 0
|
|
+#define UN_DP_M 0x0f
|
|
+
|
|
+#define GDMA_EG_CTRL_REG 0x004
|
|
+#define GDMA_CPU_BRIDGE_EN BIT(31)
|
|
+
|
|
+#define GDMA_MAC_LSB_REG 0x008
|
|
+
|
|
+#define GDMA_MAC_MSB_REG 0x00c
|
|
+
|
|
+/* MYMAC_DP/BC_DP/MC_DP/UN_DP: Destination ports */
|
|
+#define DP_PDMA 0
|
|
+#define DP_GDMA1 1
|
|
+#define DP_GDMA2 2
|
|
+#define DP_PPE 4
|
|
+#define DP_QDMA 5
|
|
+#define DP_DISCARD 7
|
|
+
|
|
+/* GMAC Registers */
|
|
+#define GMAC_PPSC_REG 0x0000
|
|
+#define PHY_MDC_CFG GENMASK(29, 24)
|
|
+#define MDC_TURBO BIT(20)
|
|
+#define MDC_MAX_FREQ 25000000
|
|
+#define MDC_MAX_DIVIDER 63
|
|
+
|
|
+#define GMAC_PIAC_REG 0x0004
|
|
+#define PHY_ACS_ST BIT(31)
|
|
+#define MDIO_REG_ADDR_S 25
|
|
+#define MDIO_REG_ADDR_M 0x3e000000
|
|
+#define MDIO_PHY_ADDR_S 20
|
|
+#define MDIO_PHY_ADDR_M 0x1f00000
|
|
+#define MDIO_CMD_S 18
|
|
+#define MDIO_CMD_M 0xc0000
|
|
+#define MDIO_ST_S 16
|
|
+#define MDIO_ST_M 0x30000
|
|
+#define MDIO_RW_DATA_S 0
|
|
+#define MDIO_RW_DATA_M 0xffff
|
|
+
|
|
+#define GMAC_XGMAC_STS_REG 0x000c
|
|
+#define P1_XGMAC_FORCE_LINK BIT(15)
|
|
+
|
|
+#define GMAC_MAC_MISC_REG 0x0010
|
|
+#define MISC_MDC_TURBO BIT(4)
|
|
+
|
|
+#define GMAC_GSW_CFG_REG 0x0080
|
|
+#define GSWTX_IPG_M 0xF0000
|
|
+#define GSWTX_IPG_S 16
|
|
+#define GSWRX_IPG_M 0xF
|
|
+#define GSWRX_IPG_S 0
|
|
+
|
|
+/* MDIO_CMD: MDIO commands */
|
|
+#define MDIO_CMD_ADDR 0
|
|
+#define MDIO_CMD_WRITE 1
|
|
+#define MDIO_CMD_READ 2
|
|
+#define MDIO_CMD_READ_C45 3
|
|
+
|
|
+/* MDIO_ST: MDIO start field */
|
|
+#define MDIO_ST_C45 0
|
|
+#define MDIO_ST_C22 1
|
|
+
|
|
+#define GMAC_PORT_MCR(p) (0x0100 + (p) * 0x100)
|
|
+#define MAC_RX_PKT_LEN_S 24
|
|
+#define MAC_RX_PKT_LEN_M 0x3000000
|
|
+#define IPG_CFG_S 18
|
|
+#define IPG_CFG_M 0xc0000
|
|
+#define MAC_MODE BIT(16)
|
|
+#define FORCE_MODE BIT(15)
|
|
+#define MAC_TX_EN BIT(14)
|
|
+#define MAC_RX_EN BIT(13)
|
|
+#define DEL_RXFIFO_CLR BIT(12)
|
|
+#define BKOFF_EN BIT(9)
|
|
+#define BACKPR_EN BIT(8)
|
|
+#define FORCE_RX_FC BIT(5)
|
|
+#define FORCE_TX_FC BIT(4)
|
|
+#define FORCE_SPD_S 2
|
|
+#define FORCE_SPD_M 0x0c
|
|
+#define FORCE_DPX BIT(1)
|
|
+#define FORCE_LINK BIT(0)
|
|
+
|
|
+/* Values of IPG_CFG */
|
|
+#define IPG_96BIT 0
|
|
+#define IPG_96BIT_WITH_SHORT_IPG 1
|
|
+#define IPG_64BIT 2
|
|
+
|
|
+/* MAC_RX_PKT_LEN: Max RX packet length */
|
|
+#define MAC_RX_PKT_LEN_1518 0
|
|
+#define MAC_RX_PKT_LEN_1536 1
|
|
+#define MAC_RX_PKT_LEN_1552 2
|
|
+#define MAC_RX_PKT_LEN_JUMBO 3
|
|
+
|
|
+/* FORCE_SPD: Forced link speed */
|
|
+#define SPEED_10M 0
|
|
+#define SPEED_100M 1
|
|
+#define SPEED_1000M 2
|
|
+
|
|
+#define GMAC_TRGMII_RCK_CTRL 0x300
|
|
+#define RX_RST BIT(31)
|
|
+#define RXC_DQSISEL BIT(30)
|
|
+
|
|
+#define NUM_TRGMII_CTRL 5
|
|
+
|
|
+#define GMAC_TRGMII_TD_ODT(n) (0x354 + (n) * 8)
|
|
+#define TD_DM_DRVN_S 4
|
|
+#define TD_DM_DRVN_M 0xf0
|
|
+#define TD_DM_DRVP_S 0
|
|
+#define TD_DM_DRVP_M 0x0f
|
|
+
|
|
+/* XGMAC Status Registers */
|
|
+#define XGMAC_STS(x) (((x) == 2) ? 0x001C : 0x000C)
|
|
+#define XGMAC_FORCE_LINK(x) (((x) == 1) ? BIT(31) : BIT(15))
|
|
+
|
|
+/* XGMAC Registers */
|
|
+#define XGMAC_PORT_MCR(x) (0x2000 + (((x) - 1) * 0x1000))
|
|
+#define XGMAC_TRX_DISABLE 0xf
|
|
+#define XGMAC_FORCE_TX_FC BIT(5)
|
|
+#define XGMAC_FORCE_RX_FC BIT(4)
|
|
+
|
|
+/* MDIO Indirect Access Registers */
|
|
+#define MII_MMD_ACC_CTL_REG 0x0d
|
|
+#define MMD_CMD_S 14
|
|
+#define MMD_CMD_M 0xc000
|
|
+#define MMD_DEVAD_S 0
|
|
+#define MMD_DEVAD_M 0x1f
|
|
+
|
|
+/* MMD_CMD: MMD commands */
|
|
+#define MMD_ADDR 0
|
|
+#define MMD_DATA 1
|
|
+#define MMD_DATA_RW_POST_INC 2
|
|
+#define MMD_DATA_W_POST_INC 3
|
|
+
|
|
+#define MII_MMD_ADDR_DATA_REG 0x0e
|
|
+
|
|
+/* PDMA descriptors */
|
|
+struct mtk_rx_dma {
|
|
+ unsigned int rxd1;
|
|
+ unsigned int rxd2;
|
|
+ unsigned int rxd3;
|
|
+ unsigned int rxd4;
|
|
+} __packed __aligned(4);
|
|
+
|
|
+struct mtk_rx_dma_v2 {
|
|
+ unsigned int rxd1;
|
|
+ unsigned int rxd2;
|
|
+ unsigned int rxd3;
|
|
+ unsigned int rxd4;
|
|
+ unsigned int rxd5;
|
|
+ unsigned int rxd6;
|
|
+ unsigned int rxd7;
|
|
+ unsigned int rxd8;
|
|
+} __packed __aligned(4);
|
|
+
|
|
+struct mtk_tx_dma {
|
|
+ unsigned int txd1;
|
|
+ unsigned int txd2;
|
|
+ unsigned int txd3;
|
|
+ unsigned int txd4;
|
|
+} __packed __aligned(4);
|
|
+
|
|
+struct mtk_tx_dma_v2 {
|
|
+ unsigned int txd1;
|
|
+ unsigned int txd2;
|
|
+ unsigned int txd3;
|
|
+ unsigned int txd4;
|
|
+ unsigned int txd5;
|
|
+ unsigned int txd6;
|
|
+ unsigned int txd7;
|
|
+ unsigned int txd8;
|
|
+} __packed __aligned(4);
|
|
+
|
|
+/* PDMA TXD fields */
|
|
+#define PDMA_TXD2_DDONE BIT(31)
|
|
+#define PDMA_TXD2_LS0 BIT(30)
|
|
+#define PDMA_V1_TXD2_SDL0_M GENMASK(29, 16)
|
|
+#define PDMA_V1_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V1_TXD2_SDL0_M, (_v))
|
|
+#define PDMA_V2_TXD2_SDL0_M GENMASK(23, 8)
|
|
+#define PDMA_V2_TXD2_SDL0_SET(_v) FIELD_PREP(PDMA_V2_TXD2_SDL0_M, (_v))
|
|
+
|
|
+#define PDMA_V1_TXD4_FPORT_M GENMASK(27, 25)
|
|
+#define PDMA_V1_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V1_TXD4_FPORT_M, (_v))
|
|
+#define PDMA_V2_TXD4_FPORT_M GENMASK(27, 24)
|
|
+#define PDMA_V2_TXD4_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD4_FPORT_M, (_v))
|
|
+
|
|
+#define PDMA_V2_TXD5_FPORT_M GENMASK(19, 16)
|
|
+#define PDMA_V2_TXD5_FPORT_SET(_v) FIELD_PREP(PDMA_V2_TXD5_FPORT_M, (_v))
|
|
+
|
|
+/* PDMA RXD fields */
|
|
+#define PDMA_RXD2_DDONE BIT(31)
|
|
+#define PDMA_RXD2_LS0 BIT(30)
|
|
+#define PDMA_V1_RXD2_PLEN0_M GENMASK(29, 16)
|
|
+#define PDMA_V1_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V1_RXD2_PLEN0_M, (_v))
|
|
+#define PDMA_V1_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V1_RXD2_PLEN0_M, (_v))
|
|
+#define PDMA_V2_RXD2_PLEN0_M GENMASK(23, 8)
|
|
+#define PDMA_V2_RXD2_PLEN0_GET(_v) FIELD_GET(PDMA_V2_RXD2_PLEN0_M, (_v))
|
|
+#define PDMA_V2_RXD2_PLEN0_SET(_v) FIELD_PREP(PDMA_V2_RXD2_PLEN0_M, (_v))
|
|
+
|
|
+void mtk_fe_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
|
|
+void mtk_gmac_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
|
|
+void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, u32 set);
|
|
+
|
|
+int mtk_mii_read(struct mtk_eth_priv *priv, u8 phy, u8 reg);
|
|
+int mtk_mii_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data);
|
|
+int mtk_mmd_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
|
|
+int mtk_mmd_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
|
|
+ u16 val);
|
|
+int mtk_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg);
|
|
+int mtk_mmd_ind_write(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg,
|
|
+ u16 val);
|
|
+
|
|
+#endif /* _MTK_ETH_H_ */
|