From 626cdca5b68acdc72d2533e2ed2306c06f296725 Mon Sep 17 00:00:00 2001 From: Weijie Gao 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 --- 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 + +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 + * Author: Mark Lee + */ + +#include +#include +#include +#include +#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 + * Author: Mark Lee + */ + +#include +#include +#include +#include +#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 + * Author: Mark Lee + */ + +#include +#include +#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 + * Author: Mark Lee + */ + +#ifndef _MTK_ETH_MT753X_H_ +#define _MTK_ETH_MT753X_H_ + +#include +#include +#include +#include + +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 + * Author: Mark Lee + */ + +#include +#include +#include +#include +#include +#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 - * Author: Mark Lee - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 + * Author: Mark Lee + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 - * Author: Mark Lee - */ - -#ifndef _MTK_ETH_H_ -#define _MTK_ETH_H_ - -#include -#include - -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 + * Author: Mark Lee + */ + +#ifndef _MTK_ETH_H_ +#define _MTK_ETH_H_ + +#include +#include +#include + +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_ */