mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-13 15:03:58 +03:00
net: mediatek: split ethernet switch code from mtk_eth.c
mtk_eth.c contains not only the ethernet GMAC/DMA driver, but also some ethernet switch initialization code. As we may add more switch support in the future, it's better to move them out of mtk_eth.c to avoid increasing the code complexity. Since not all switches are supported for a particular board, Kconfig options are added to allow user to select which switch should be built into u-boot. If multiple switches are selected, auto-detecting can also be enabled. Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -68,7 +68,7 @@ obj-$(CONFIG_MDIO_MUX_MESON_GXL) += mdio_mux_meson_gxl.o
|
||||
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
|
||||
|
||||
35
drivers/net/mtk_eth/Kconfig
Normal file
35
drivers/net/mtk_eth/Kconfig
Normal file
@@ -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
|
||||
9
drivers/net/mtk_eth/Makefile
Normal file
9
drivers/net/mtk_eth/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright (C) 2025 MediaTek Inc.
|
||||
# Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
|
||||
obj-y += mtk_eth.o
|
||||
obj-$(CONFIG_MTK_ETH_SWITCH_MT7530) += mt753x.o mt7530.o
|
||||
obj-$(CONFIG_MTK_ETH_SWITCH_MT7531) += mt753x.o mt7531.o
|
||||
obj-$(CONFIG_MTK_ETH_SWITCH_MT7988) += mt753x.o mt7988.o
|
||||
281
drivers/net/mtk_eth/mt7530.c
Normal file
281
drivers/net/mtk_eth/mt7530.c
Normal file
@@ -0,0 +1,281 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 MediaTek Inc.
|
||||
*
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
* Author: Mark Lee <mark-mc.lee@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <miiphy.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/mii.h>
|
||||
#include "mtk_eth.h"
|
||||
#include "mt753x.h"
|
||||
|
||||
#define CHIP_REV 0x7ffc
|
||||
#define CHIP_NAME_S 16
|
||||
#define CHIP_NAME_M 0xffff0000
|
||||
#define CHIP_REV_S 0
|
||||
#define CHIP_REV_M 0x0f
|
||||
|
||||
static void mt7530_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
|
||||
u32 val)
|
||||
{
|
||||
u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
|
||||
|
||||
mtk_mmd_ind_write(priv->epriv.eth, phy_addr, 0x1f, reg, val);
|
||||
}
|
||||
|
||||
static int mt7530_pad_clk_setup(struct mt753x_switch_priv *priv, int mode)
|
||||
{
|
||||
u32 ncpo1, ssc_delta;
|
||||
|
||||
switch (mode) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
ncpo1 = 0x0c80;
|
||||
ssc_delta = 0x87;
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("error: xMII mode %d is not supported\n", mode);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Disable MT7530 core clock */
|
||||
mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, 0);
|
||||
|
||||
/* Disable MT7530 PLL */
|
||||
mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
|
||||
(2 << RG_GSWPLL_POSDIV_200M_S) |
|
||||
(32 << RG_GSWPLL_FBKDIV_200M_S));
|
||||
|
||||
/* For MT7530 core clock = 500Mhz */
|
||||
mt7530_core_reg_write(priv, CORE_GSWPLL_GRP2,
|
||||
(1 << RG_GSWPLL_POSDIV_500M_S) |
|
||||
(25 << RG_GSWPLL_FBKDIV_500M_S));
|
||||
|
||||
/* Enable MT7530 PLL */
|
||||
mt7530_core_reg_write(priv, CORE_GSWPLL_GRP1,
|
||||
(2 << RG_GSWPLL_POSDIV_200M_S) |
|
||||
(32 << RG_GSWPLL_FBKDIV_200M_S) |
|
||||
RG_GSWPLL_EN_PRE);
|
||||
|
||||
udelay(20);
|
||||
|
||||
mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG, REG_GSWCK_EN);
|
||||
|
||||
/* Setup the MT7530 TRGMII Tx Clock */
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP5, ncpo1);
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP6, 0);
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP10, ssc_delta);
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP11, ssc_delta);
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP4, RG_SYSPLL_DDSFBK_EN |
|
||||
RG_SYSPLL_BIAS_EN | RG_SYSPLL_BIAS_LPF_EN);
|
||||
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP2,
|
||||
RG_SYSPLL_EN_NORMAL | RG_SYSPLL_VODEN |
|
||||
(1 << RG_SYSPLL_POSDIV_S));
|
||||
|
||||
mt7530_core_reg_write(priv, CORE_PLL_GROUP7,
|
||||
RG_LCDDS_PCW_NCPO_CHG | (3 << RG_LCCDS_C_S) |
|
||||
RG_LCDDS_PWDB | RG_LCDDS_ISO_EN);
|
||||
|
||||
/* Enable MT7530 core clock */
|
||||
mt7530_core_reg_write(priv, CORE_TRGMII_GSW_CLK_CG,
|
||||
REG_GSWCK_EN | REG_TRGMIICK_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt7530_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
u32 pmcr = FORCE_MODE;
|
||||
|
||||
if (enable)
|
||||
pmcr = priv->pmcr;
|
||||
|
||||
mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
||||
}
|
||||
|
||||
static int mt7530_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = bus->priv;
|
||||
|
||||
if (devad < 0)
|
||||
return mtk_mii_read(priv->epriv.eth, addr, reg);
|
||||
|
||||
return mtk_mmd_ind_read(priv->epriv.eth, addr, devad, reg);
|
||||
}
|
||||
|
||||
static int mt7530_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
||||
u16 val)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = bus->priv;
|
||||
|
||||
if (devad < 0)
|
||||
return mtk_mii_write(priv->epriv.eth, addr, reg, val);
|
||||
|
||||
return mtk_mmd_ind_write(priv->epriv.eth, addr, devad, reg, val);
|
||||
}
|
||||
|
||||
static int mt7530_mdio_register(struct mt753x_switch_priv *priv)
|
||||
{
|
||||
struct mii_dev *mdio_bus = mdio_alloc();
|
||||
int ret;
|
||||
|
||||
if (!mdio_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
mdio_bus->read = mt7530_mdio_read;
|
||||
mdio_bus->write = mt7530_mdio_write;
|
||||
snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
|
||||
|
||||
mdio_bus->priv = priv;
|
||||
|
||||
ret = mdio_register(mdio_bus);
|
||||
if (ret) {
|
||||
mdio_free(mdio_bus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->mdio_bus = mdio_bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7530_setup(struct mtk_eth_switch_priv *swpriv)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
u16 phy_addr, phy_val;
|
||||
u32 i, val, txdrv;
|
||||
|
||||
priv->smi_addr = MT753X_DFL_SMI_ADDR;
|
||||
priv->reg_read = mt753x_mdio_reg_read;
|
||||
priv->reg_write = mt753x_mdio_reg_write;
|
||||
|
||||
if (!MTK_HAS_CAPS(priv->epriv.soc->caps, MTK_TRGMII_MT7621_CLK)) {
|
||||
/* Select 250MHz clk for RGMII mode */
|
||||
mtk_ethsys_rmw(priv->epriv.eth, ETHSYS_CLKCFG0_REG,
|
||||
ETHSYS_TRGMII_CLK_SEL362_5, 0);
|
||||
|
||||
txdrv = 8;
|
||||
} else {
|
||||
txdrv = 4;
|
||||
}
|
||||
|
||||
/* Modify HWTRAP first to allow direct access to internal PHYs */
|
||||
mt753x_reg_read(priv, HWTRAP_REG, &val);
|
||||
val |= CHG_TRAP;
|
||||
val &= ~C_MDIO_BPS;
|
||||
mt753x_reg_write(priv, MHWTRAP_REG, val);
|
||||
|
||||
/* Calculate the phy base address */
|
||||
val = ((val & SMI_ADDR_M) >> SMI_ADDR_S) << 3;
|
||||
priv->phy_base = (val | 0x7) + 1;
|
||||
|
||||
/* Turn off PHYs */
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
||||
phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
|
||||
phy_val |= BMCR_PDOWN;
|
||||
mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
|
||||
}
|
||||
|
||||
/* Force MAC link down before reset */
|
||||
mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
|
||||
mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
|
||||
|
||||
/* MT7530 reset */
|
||||
mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
|
||||
udelay(100);
|
||||
|
||||
val = (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
||||
MAC_MODE | FORCE_MODE |
|
||||
MAC_TX_EN | MAC_RX_EN |
|
||||
BKOFF_EN | BACKPR_EN |
|
||||
(SPEED_1000M << FORCE_SPD_S) |
|
||||
FORCE_DPX | FORCE_LINK;
|
||||
|
||||
/* MT7530 Port6: Forced 1000M/FD, FC disabled */
|
||||
priv->pmcr = val;
|
||||
|
||||
/* MT7530 Port5: Forced link down */
|
||||
mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE);
|
||||
|
||||
/* Keep MAC link down before starting eth */
|
||||
mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE);
|
||||
|
||||
/* MT7530 Port6: Set to RGMII */
|
||||
mt753x_reg_rmw(priv, MT7530_P6ECR, P6_INTF_MODE_M, P6_INTF_MODE_RGMII);
|
||||
|
||||
/* Hardware Trap: Enable Port6, Disable Port5 */
|
||||
mt753x_reg_read(priv, HWTRAP_REG, &val);
|
||||
val |= CHG_TRAP | LOOPDET_DIS | P5_INTF_DIS |
|
||||
(P5_INTF_SEL_GMAC5 << P5_INTF_SEL_S) |
|
||||
(P5_INTF_MODE_RGMII << P5_INTF_MODE_S);
|
||||
val &= ~(C_MDIO_BPS | P6_INTF_DIS);
|
||||
mt753x_reg_write(priv, MHWTRAP_REG, val);
|
||||
|
||||
/* Setup switch core pll */
|
||||
mt7530_pad_clk_setup(priv, priv->epriv.phy_interface);
|
||||
|
||||
/* Lower Tx Driving for TRGMII path */
|
||||
for (i = 0 ; i < NUM_TRGMII_CTRL ; i++)
|
||||
mt753x_reg_write(priv, MT7530_TRGMII_TD_ODT(i),
|
||||
(txdrv << TD_DM_DRVP_S) |
|
||||
(txdrv << TD_DM_DRVN_S));
|
||||
|
||||
for (i = 0 ; i < NUM_TRGMII_CTRL; i++)
|
||||
mt753x_reg_rmw(priv, MT7530_TRGMII_RD(i), RD_TAP_M, 16);
|
||||
|
||||
/* Enable port isolation to block inter-port communication */
|
||||
mt753x_port_isolation(priv);
|
||||
|
||||
/* Turn on PHYs */
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
||||
phy_val = mtk_mii_read(priv->epriv.eth, phy_addr, MII_BMCR);
|
||||
phy_val &= ~BMCR_PDOWN;
|
||||
mtk_mii_write(priv->epriv.eth, phy_addr, MII_BMCR, phy_val);
|
||||
}
|
||||
|
||||
return mt7530_mdio_register(priv);
|
||||
}
|
||||
|
||||
static int mt7530_cleanup(struct mtk_eth_switch_priv *swpriv)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
|
||||
mdio_unregister(priv->mdio_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7530_detect(struct mtk_eth_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 rev;
|
||||
|
||||
ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7530)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
MTK_ETH_SWITCH(mt7530) = {
|
||||
.name = "mt7530",
|
||||
.desc = "MediaTek MT7530",
|
||||
.priv_size = sizeof(struct mt753x_switch_priv),
|
||||
.reset_wait_time = 1000,
|
||||
|
||||
.detect = mt7530_detect,
|
||||
.setup = mt7530_setup,
|
||||
.cleanup = mt7530_cleanup,
|
||||
.mac_control = mt7530_mac_control,
|
||||
};
|
||||
293
drivers/net/mtk_eth/mt7531.c
Normal file
293
drivers/net/mtk_eth/mt7531.c
Normal file
@@ -0,0 +1,293 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 MediaTek Inc.
|
||||
*
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
* Author: Mark Lee <mark-mc.lee@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <miiphy.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/mii.h>
|
||||
#include "mtk_eth.h"
|
||||
#include "mt753x.h"
|
||||
|
||||
#define CHIP_REV 0x781C
|
||||
#define CHIP_NAME_S 16
|
||||
#define CHIP_NAME_M 0xffff0000
|
||||
#define CHIP_REV_S 0
|
||||
#define CHIP_REV_M 0x0f
|
||||
#define CHIP_REV_E1 0x0
|
||||
|
||||
static int mt7531_core_reg_read(struct mt753x_switch_priv *priv, u32 reg)
|
||||
{
|
||||
u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
|
||||
|
||||
return mt7531_mmd_read(priv, phy_addr, 0x1f, reg);
|
||||
}
|
||||
|
||||
static void mt7531_core_reg_write(struct mt753x_switch_priv *priv, u32 reg,
|
||||
u32 val)
|
||||
{
|
||||
u8 phy_addr = MT753X_PHY_ADDR(priv->phy_base, 0);
|
||||
|
||||
mt7531_mmd_write(priv, phy_addr, 0x1f, reg, val);
|
||||
}
|
||||
|
||||
static void mt7531_core_pll_setup(struct mt753x_switch_priv *priv)
|
||||
{
|
||||
/* Step 1 : Disable MT7531 COREPLL */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, 0);
|
||||
|
||||
/* Step 2: switch to XTAL output */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_CLKSW, SW_CLKSW);
|
||||
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, 0);
|
||||
|
||||
/* Step 3: disable PLLGP and enable program PLLGP */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_EN, SW_PLLGP, SW_PLLGP);
|
||||
|
||||
/* Step 4: program COREPLL output frequency to 500MHz */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_POSDIV_M,
|
||||
2 << RG_COREPLL_POSDIV_S);
|
||||
udelay(25);
|
||||
|
||||
/* Currently, support XTAL 25Mhz only */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_M,
|
||||
0x140000 << RG_COREPLL_SDM_PCW_S);
|
||||
|
||||
/* Set feedback divide ratio update signal to high */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG,
|
||||
RG_COREPLL_SDM_PCW_CHG);
|
||||
|
||||
/* Wait for at least 16 XTAL clocks */
|
||||
udelay(10);
|
||||
|
||||
/* Step 5: set feedback divide ratio update signal to low */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_SDM_PCW_CHG, 0);
|
||||
|
||||
/* add enable 325M clock for SGMII */
|
||||
mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR5, 0xad0000);
|
||||
|
||||
/* add enable 250SSC clock for RGMII */
|
||||
mt753x_reg_write(priv, MT7531_ANA_PLLGP_CR2, 0x4f40000);
|
||||
|
||||
/*Step 6: Enable MT7531 PLL */
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_CR0, RG_COREPLL_EN, RG_COREPLL_EN);
|
||||
|
||||
mt753x_reg_rmw(priv, MT7531_PLLGP_EN, EN_COREPLL, EN_COREPLL);
|
||||
|
||||
udelay(25);
|
||||
}
|
||||
|
||||
static int mt7531_port_sgmii_init(struct mt753x_switch_priv *priv, u32 port)
|
||||
{
|
||||
if (port != 5 && port != 6) {
|
||||
printf("mt7531: port %d is not a SGMII port\n", port);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Set SGMII GEN2 speed(2.5G) */
|
||||
mt753x_reg_rmw(priv, MT7531_PHYA_CTRL_SIGNAL3(port), SGMSYS_SPEED_MASK,
|
||||
FIELD_PREP(SGMSYS_SPEED_MASK, SGMSYS_SPEED_2500));
|
||||
|
||||
/* Disable SGMII AN */
|
||||
mt753x_reg_rmw(priv, MT7531_PCS_CONTROL_1(port),
|
||||
SGMII_AN_ENABLE, 0);
|
||||
|
||||
/* SGMII force mode setting */
|
||||
mt753x_reg_write(priv, MT7531_SGMII_MODE(port), SGMII_FORCE_MODE);
|
||||
|
||||
/* Release PHYA power down state */
|
||||
mt753x_reg_rmw(priv, MT7531_QPHY_PWR_STATE_CTRL(port),
|
||||
SGMII_PHYA_PWD, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7531_port_rgmii_init(struct mt753x_switch_priv *priv, u32 port)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (port != 5) {
|
||||
printf("error: RGMII mode is not available for port %d\n",
|
||||
port);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mt753x_reg_read(priv, MT7531_CLKGEN_CTRL, &val);
|
||||
val |= GP_CLK_EN;
|
||||
val &= ~GP_MODE_M;
|
||||
val |= GP_MODE_RGMII << GP_MODE_S;
|
||||
val |= TXCLK_NO_REVERSE;
|
||||
val |= RXCLK_NO_DELAY;
|
||||
val &= ~CLK_SKEW_IN_M;
|
||||
val |= CLK_SKEW_IN_NO_CHANGE << CLK_SKEW_IN_S;
|
||||
val &= ~CLK_SKEW_OUT_M;
|
||||
val |= CLK_SKEW_OUT_NO_CHANGE << CLK_SKEW_OUT_S;
|
||||
mt753x_reg_write(priv, MT7531_CLKGEN_CTRL, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt7531_phy_setting(struct mt753x_switch_priv *priv)
|
||||
{
|
||||
int i;
|
||||
u32 val;
|
||||
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
/* Enable HW auto downshift */
|
||||
mt7531_mii_write(priv, i, 0x1f, 0x1);
|
||||
val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
|
||||
val |= PHY_EN_DOWN_SHFIT;
|
||||
mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
|
||||
|
||||
/* PHY link down power saving enable */
|
||||
val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
|
||||
val |= PHY_LINKDOWN_POWER_SAVING_EN;
|
||||
mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
|
||||
|
||||
val = mt7531_mmd_read(priv, i, 0x1e, PHY_DEV1E_REG_0C6);
|
||||
val &= ~PHY_POWER_SAVING_M;
|
||||
val |= PHY_POWER_SAVING_TX << PHY_POWER_SAVING_S;
|
||||
mt7531_mmd_write(priv, i, 0x1e, PHY_DEV1E_REG_0C6, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void mt7531_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
u32 pmcr = FORCE_MODE_LNK;
|
||||
|
||||
if (enable)
|
||||
pmcr = priv->pmcr;
|
||||
|
||||
mt753x_reg_write(priv, PMCR_REG(5), pmcr);
|
||||
mt753x_reg_write(priv, PMCR_REG(6), pmcr);
|
||||
}
|
||||
|
||||
static int mt7531_setup(struct mtk_eth_switch_priv *swpriv)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
u32 i, val, pmcr, port5_sgmii;
|
||||
u16 phy_addr, phy_val;
|
||||
|
||||
priv->smi_addr = MT753X_DFL_SMI_ADDR;
|
||||
priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
|
||||
priv->reg_read = mt753x_mdio_reg_read;
|
||||
priv->reg_write = mt753x_mdio_reg_write;
|
||||
|
||||
/* Turn off PHYs */
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
||||
phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
||||
phy_val |= BMCR_PDOWN;
|
||||
mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
||||
}
|
||||
|
||||
/* Force MAC link down before reset */
|
||||
mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
|
||||
mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
||||
|
||||
/* Switch soft reset */
|
||||
mt753x_reg_write(priv, SYS_CTRL_REG, SW_SYS_RST | SW_REG_RST);
|
||||
udelay(100);
|
||||
|
||||
/* Enable MDC input Schmitt Trigger */
|
||||
mt753x_reg_rmw(priv, MT7531_SMT0_IOLB, SMT_IOLB_5_SMI_MDC_EN,
|
||||
SMT_IOLB_5_SMI_MDC_EN);
|
||||
|
||||
mt7531_core_pll_setup(priv);
|
||||
|
||||
mt753x_reg_read(priv, MT7531_TOP_SIG_SR, &val);
|
||||
port5_sgmii = !!(val & PAD_DUAL_SGMII_EN);
|
||||
|
||||
/* port5 support either RGMII or SGMII, port6 only support SGMII. */
|
||||
switch (priv->epriv.phy_interface) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
if (!port5_sgmii)
|
||||
mt7531_port_rgmii_init(priv, 5);
|
||||
break;
|
||||
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
mt7531_port_sgmii_init(priv, 6);
|
||||
if (port5_sgmii)
|
||||
mt7531_port_sgmii_init(priv, 5);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
pmcr = MT7531_FORCE_MODE |
|
||||
(IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
||||
MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
||||
BKOFF_EN | BACKPR_EN |
|
||||
FORCE_RX_FC | FORCE_TX_FC |
|
||||
(SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
|
||||
FORCE_LINK;
|
||||
|
||||
priv->pmcr = pmcr;
|
||||
|
||||
/* Keep MAC link down before starting eth */
|
||||
mt753x_reg_write(priv, PMCR_REG(5), FORCE_MODE_LNK);
|
||||
mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
||||
|
||||
/* Enable port isolation to block inter-port communication */
|
||||
mt753x_port_isolation(priv);
|
||||
|
||||
/* Turn on PHYs */
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
||||
phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
||||
phy_val &= ~BMCR_PDOWN;
|
||||
mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
||||
}
|
||||
|
||||
mt7531_phy_setting(priv);
|
||||
|
||||
/* Enable Internal PHYs */
|
||||
val = mt7531_core_reg_read(priv, CORE_PLL_GROUP4);
|
||||
val |= MT7531_BYPASS_MODE;
|
||||
val &= ~MT7531_POWER_ON_OFF;
|
||||
mt7531_core_reg_write(priv, CORE_PLL_GROUP4, val);
|
||||
|
||||
return mt7531_mdio_register(priv);
|
||||
}
|
||||
|
||||
static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
|
||||
mdio_unregister(priv->mdio_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7531_detect(struct mtk_eth_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 rev;
|
||||
|
||||
ret = __mt753x_mdio_reg_read(priv, MT753X_DFL_SMI_ADDR, CHIP_REV, &rev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (((rev & CHIP_NAME_M) >> CHIP_NAME_S) == 0x7531)
|
||||
return 0;
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
MTK_ETH_SWITCH(mt7531) = {
|
||||
.name = "mt7531",
|
||||
.desc = "MediaTek MT7531",
|
||||
.priv_size = sizeof(struct mt753x_switch_priv),
|
||||
.reset_wait_time = 200,
|
||||
|
||||
.detect = mt7531_detect,
|
||||
.setup = mt7531_setup,
|
||||
.cleanup = mt7531_cleanup,
|
||||
.mac_control = mt7531_mac_control,
|
||||
};
|
||||
262
drivers/net/mtk_eth/mt753x.c
Normal file
262
drivers/net/mtk_eth/mt753x.c
Normal file
@@ -0,0 +1,262 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 MediaTek Inc.
|
||||
*
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
* Author: Mark Lee <mark-mc.lee@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include "mtk_eth.h"
|
||||
#include "mt753x.h"
|
||||
|
||||
/*
|
||||
* MT753x Internal Register Address Bits
|
||||
* -------------------------------------------------------------------
|
||||
* | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 |
|
||||
* |----------------------------------------|---------------|--------|
|
||||
* | Page Address | Reg Address | Unused |
|
||||
* -------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
|
||||
u32 *data)
|
||||
{
|
||||
int ret, low_word, high_word;
|
||||
|
||||
/* Write page address */
|
||||
ret = mtk_mii_write(priv, smi_addr, 0x1f, reg >> 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Read low word */
|
||||
low_word = mtk_mii_read(priv, smi_addr, (reg >> 2) & 0xf);
|
||||
if (low_word < 0)
|
||||
return low_word;
|
||||
|
||||
/* Read high word */
|
||||
high_word = mtk_mii_read(priv, smi_addr, 0x10);
|
||||
if (high_word < 0)
|
||||
return high_word;
|
||||
|
||||
if (data)
|
||||
*data = ((u32)high_word << 16) | (low_word & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
|
||||
{
|
||||
return __mt753x_mdio_reg_read(priv->epriv.eth, priv->smi_addr, reg,
|
||||
data);
|
||||
}
|
||||
|
||||
int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Write page address */
|
||||
ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x1f, reg >> 6);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write low word */
|
||||
ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, (reg >> 2) & 0xf,
|
||||
data & 0xffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Write high word */
|
||||
return mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x10, data >> 16);
|
||||
}
|
||||
|
||||
int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
|
||||
{
|
||||
return priv->reg_read(priv, reg, data);
|
||||
}
|
||||
|
||||
int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
|
||||
{
|
||||
return priv->reg_write(priv, reg, data);
|
||||
}
|
||||
|
||||
void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
priv->reg_read(priv, reg, &val);
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
priv->reg_write(priv, reg, val);
|
||||
}
|
||||
|
||||
/* Indirect MDIO clause 22/45 access */
|
||||
static int mt7531_mii_rw(struct mt753x_switch_priv *priv, int phy, int reg,
|
||||
u16 data, u32 cmd, u32 st)
|
||||
{
|
||||
u32 val, timeout_ms;
|
||||
ulong timeout;
|
||||
int ret = 0;
|
||||
|
||||
val = (st << MDIO_ST_S) |
|
||||
((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
|
||||
((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
|
||||
((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
|
||||
|
||||
if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
|
||||
val |= data & MDIO_RW_DATA_M;
|
||||
|
||||
mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
|
||||
|
||||
timeout_ms = 100;
|
||||
timeout = get_timer(0);
|
||||
while (1) {
|
||||
mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
|
||||
|
||||
if ((val & PHY_ACS_ST) == 0)
|
||||
break;
|
||||
|
||||
if (get_timer(timeout) > timeout_ms)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
|
||||
mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
|
||||
ret = val & MDIO_RW_DATA_M;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg)
|
||||
{
|
||||
u8 phy_addr;
|
||||
|
||||
if (phy >= MT753X_NUM_PHYS)
|
||||
return -EINVAL;
|
||||
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
|
||||
|
||||
return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
|
||||
MDIO_ST_C22);
|
||||
}
|
||||
|
||||
int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val)
|
||||
{
|
||||
u8 phy_addr;
|
||||
|
||||
if (phy >= MT753X_NUM_PHYS)
|
||||
return -EINVAL;
|
||||
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
|
||||
|
||||
return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
|
||||
MDIO_ST_C22);
|
||||
}
|
||||
|
||||
int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
||||
u16 reg)
|
||||
{
|
||||
u8 phy_addr;
|
||||
int ret;
|
||||
|
||||
if (addr >= MT753X_NUM_PHYS)
|
||||
return -EINVAL;
|
||||
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
|
||||
|
||||
ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
|
||||
MDIO_ST_C45);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
|
||||
MDIO_ST_C45);
|
||||
}
|
||||
|
||||
int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
||||
u16 reg, u16 val)
|
||||
{
|
||||
u8 phy_addr;
|
||||
int ret;
|
||||
|
||||
if (addr >= MT753X_NUM_PHYS)
|
||||
return 0;
|
||||
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
|
||||
|
||||
ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
|
||||
MDIO_ST_C45);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
|
||||
MDIO_ST_C45);
|
||||
}
|
||||
|
||||
static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = bus->priv;
|
||||
|
||||
if (devad < 0)
|
||||
return mt7531_mii_read(priv, addr, reg);
|
||||
|
||||
return mt7531_mmd_read(priv, addr, devad, reg);
|
||||
}
|
||||
|
||||
static int mt7531_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
|
||||
u16 val)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = bus->priv;
|
||||
|
||||
if (devad < 0)
|
||||
return mt7531_mii_write(priv, addr, reg, val);
|
||||
|
||||
return mt7531_mmd_write(priv, addr, devad, reg, val);
|
||||
}
|
||||
|
||||
int mt7531_mdio_register(struct mt753x_switch_priv *priv)
|
||||
{
|
||||
struct mii_dev *mdio_bus = mdio_alloc();
|
||||
int ret;
|
||||
|
||||
if (!mdio_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
mdio_bus->read = mt7531_mdio_read;
|
||||
mdio_bus->write = mt7531_mdio_write;
|
||||
snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
|
||||
|
||||
mdio_bus->priv = priv;
|
||||
|
||||
ret = mdio_register(mdio_bus);
|
||||
if (ret) {
|
||||
mdio_free(mdio_bus);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->mdio_bus = mdio_bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mt753x_port_isolation(struct mt753x_switch_priv *priv)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MT753X_NUM_PORTS; i++) {
|
||||
/* Set port matrix mode */
|
||||
if (i != 6)
|
||||
mt753x_reg_write(priv, PCR_REG(i),
|
||||
(0x40 << PORT_MATRIX_S));
|
||||
else
|
||||
mt753x_reg_write(priv, PCR_REG(i),
|
||||
(0x3f << PORT_MATRIX_S));
|
||||
|
||||
/* Set port mode to user port */
|
||||
mt753x_reg_write(priv, PVC_REG(i),
|
||||
(0x8100 << STAG_VPID_S) |
|
||||
(VLAN_ATTR_USER << VLAN_ATTR_S));
|
||||
}
|
||||
}
|
||||
286
drivers/net/mtk_eth/mt753x.h
Normal file
286
drivers/net/mtk_eth/mt753x.h
Normal file
@@ -0,0 +1,286 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2025 MediaTek Inc.
|
||||
*
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
* Author: Mark Lee <mark-mc.lee@mediatek.com>
|
||||
*/
|
||||
|
||||
#ifndef _MTK_ETH_MT753X_H_
|
||||
#define _MTK_ETH_MT753X_H_
|
||||
|
||||
#include <phy.h>
|
||||
#include <miiphy.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
struct mtk_eth_priv;
|
||||
|
||||
#define MT753X_NUM_PHYS 5
|
||||
#define MT753X_NUM_PORTS 7
|
||||
#define MT753X_DFL_SMI_ADDR 31
|
||||
#define MT753X_SMI_ADDR_MASK 0x1f
|
||||
|
||||
#define MT753X_PHY_ADDR(base, addr) \
|
||||
(((base) + (addr)) & 0x1f)
|
||||
|
||||
/* MT7530 Registers */
|
||||
#define PCR_REG(p) (0x2004 + (p) * 0x100)
|
||||
#define PORT_MATRIX_S 16
|
||||
#define PORT_MATRIX_M 0xff0000
|
||||
|
||||
#define PVC_REG(p) (0x2010 + (p) * 0x100)
|
||||
#define STAG_VPID_S 16
|
||||
#define STAG_VPID_M 0xffff0000
|
||||
#define VLAN_ATTR_S 6
|
||||
#define VLAN_ATTR_M 0xc0
|
||||
|
||||
/* VLAN_ATTR: VLAN attributes */
|
||||
#define VLAN_ATTR_USER 0
|
||||
#define VLAN_ATTR_STACK 1
|
||||
#define VLAN_ATTR_TRANSLATION 2
|
||||
#define VLAN_ATTR_TRANSPARENT 3
|
||||
|
||||
#define PMCR_REG(p) (0x3000 + (p) * 0x100)
|
||||
/* XXX: all fields of MT7530 are defined under GMAC_PORT_MCR
|
||||
* MT7531 specific fields are defined below
|
||||
*/
|
||||
#define FORCE_MODE_EEE1G BIT(25)
|
||||
#define FORCE_MODE_EEE100 BIT(26)
|
||||
#define FORCE_MODE_TX_FC BIT(27)
|
||||
#define FORCE_MODE_RX_FC BIT(28)
|
||||
#define FORCE_MODE_DPX BIT(29)
|
||||
#define FORCE_MODE_SPD BIT(30)
|
||||
#define FORCE_MODE_LNK BIT(31)
|
||||
#define MT7531_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
|
||||
FORCE_MODE_DPX | FORCE_MODE_SPD | \
|
||||
FORCE_MODE_LNK
|
||||
#define MT7988_FORCE_MODE FORCE_MODE_TX_FC | FORCE_MODE_RX_FC | \
|
||||
FORCE_MODE_DPX | FORCE_MODE_SPD | \
|
||||
FORCE_MODE_LNK
|
||||
|
||||
/* MT7531 SGMII Registers */
|
||||
#define MT7531_SGMII_REG_BASE 0x5000
|
||||
#define MT7531_SGMII_REG_PORT_BASE 0x1000
|
||||
#define MT7531_SGMII_REG(p, r) (MT7531_SGMII_REG_BASE + \
|
||||
(p) * MT7531_SGMII_REG_PORT_BASE + (r))
|
||||
#define MT7531_PCS_CONTROL_1(p) MT7531_SGMII_REG(((p) - 5), 0x00)
|
||||
#define MT7531_SGMII_MODE(p) MT7531_SGMII_REG(((p) - 5), 0x20)
|
||||
#define MT7531_QPHY_PWR_STATE_CTRL(p) MT7531_SGMII_REG(((p) - 5), 0xe8)
|
||||
#define MT7531_PHYA_CTRL_SIGNAL3(p) MT7531_SGMII_REG(((p) - 5), 0x128)
|
||||
#define MT7531_PHYA_ANA_SYSPLL(p) MT7531_SGMII_REG(((p) - 5), 0x158)
|
||||
/* XXX: all fields of MT7531 SGMII are defined under SGMSYS */
|
||||
|
||||
/* MT753x System Control Register */
|
||||
#define SYS_CTRL_REG 0x7000
|
||||
#define SW_PHY_RST BIT(2)
|
||||
#define SW_SYS_RST BIT(1)
|
||||
#define SW_REG_RST BIT(0)
|
||||
|
||||
/* MT7531 */
|
||||
#define MT7531_PHY_IAC 0x701c
|
||||
/* XXX: all fields are defined under GMAC_PIAC_REG */
|
||||
|
||||
#define MT7531_CLKGEN_CTRL 0x7500
|
||||
#define CLK_SKEW_OUT_S 8
|
||||
#define CLK_SKEW_OUT_M 0x300
|
||||
#define CLK_SKEW_IN_S 6
|
||||
#define CLK_SKEW_IN_M 0xc0
|
||||
#define RXCLK_NO_DELAY BIT(5)
|
||||
#define TXCLK_NO_REVERSE BIT(4)
|
||||
#define GP_MODE_S 1
|
||||
#define GP_MODE_M 0x06
|
||||
#define GP_CLK_EN BIT(0)
|
||||
|
||||
/* Values of GP_MODE */
|
||||
#define GP_MODE_RGMII 0
|
||||
#define GP_MODE_MII 1
|
||||
#define GP_MODE_REV_MII 2
|
||||
|
||||
/* Values of CLK_SKEW_IN */
|
||||
#define CLK_SKEW_IN_NO_CHANGE 0
|
||||
#define CLK_SKEW_IN_DELAY_100PPS 1
|
||||
#define CLK_SKEW_IN_DELAY_200PPS 2
|
||||
#define CLK_SKEW_IN_REVERSE 3
|
||||
|
||||
/* Values of CLK_SKEW_OUT */
|
||||
#define CLK_SKEW_OUT_NO_CHANGE 0
|
||||
#define CLK_SKEW_OUT_DELAY_100PPS 1
|
||||
#define CLK_SKEW_OUT_DELAY_200PPS 2
|
||||
#define CLK_SKEW_OUT_REVERSE 3
|
||||
|
||||
#define HWTRAP_REG 0x7800
|
||||
/* MT7530 Modified Hardware Trap Status Registers */
|
||||
#define MHWTRAP_REG 0x7804
|
||||
#define CHG_TRAP BIT(16)
|
||||
#define LOOPDET_DIS BIT(14)
|
||||
#define P5_INTF_SEL_S 13
|
||||
#define P5_INTF_SEL_M 0x2000
|
||||
#define SMI_ADDR_S 11
|
||||
#define SMI_ADDR_M 0x1800
|
||||
#define XTAL_FSEL_S 9
|
||||
#define XTAL_FSEL_M 0x600
|
||||
#define P6_INTF_DIS BIT(8)
|
||||
#define P5_INTF_MODE_S 7
|
||||
#define P5_INTF_MODE_M 0x80
|
||||
#define P5_INTF_DIS BIT(6)
|
||||
#define C_MDIO_BPS BIT(5)
|
||||
#define CHIP_MODE_S 0
|
||||
#define CHIP_MODE_M 0x0f
|
||||
|
||||
/* P5_INTF_SEL: Interface type of Port5 */
|
||||
#define P5_INTF_SEL_GPHY 0
|
||||
#define P5_INTF_SEL_GMAC5 1
|
||||
|
||||
/* P5_INTF_MODE: Interface mode of Port5 */
|
||||
#define P5_INTF_MODE_GMII_MII 0
|
||||
#define P5_INTF_MODE_RGMII 1
|
||||
|
||||
#define MT7530_P6ECR 0x7830
|
||||
#define P6_INTF_MODE_M 0x3
|
||||
#define P6_INTF_MODE_S 0
|
||||
|
||||
/* P6_INTF_MODE: Interface mode of Port6 */
|
||||
#define P6_INTF_MODE_RGMII 0
|
||||
#define P6_INTF_MODE_TRGMII 1
|
||||
|
||||
#define MT7530_TRGMII_RD(n) (0x7a10 + (n) * 8)
|
||||
#define RD_TAP_S 0
|
||||
#define RD_TAP_M 0x7f
|
||||
|
||||
#define MT7530_TRGMII_TD_ODT(n) (0x7a54 + (n) * 8)
|
||||
/* XXX: all fields are defined under GMAC_TRGMII_TD_ODT */
|
||||
|
||||
/* TOP Signals Status Register */
|
||||
#define MT7531_TOP_SIG_SR 0x780c
|
||||
#define PAD_MCM_SMI_EN BIT(0)
|
||||
#define PAD_DUAL_SGMII_EN BIT(1)
|
||||
|
||||
/* MT7531 PLLGP Registers */
|
||||
#define MT7531_PLLGP_EN 0x7820
|
||||
#define EN_COREPLL BIT(2)
|
||||
#define SW_CLKSW BIT(1)
|
||||
#define SW_PLLGP BIT(0)
|
||||
|
||||
#define MT7531_PLLGP_CR0 0x78a8
|
||||
#define RG_COREPLL_EN BIT(22)
|
||||
#define RG_COREPLL_POSDIV_S 23
|
||||
#define RG_COREPLL_POSDIV_M 0x3800000
|
||||
#define RG_COREPLL_SDM_PCW_S 1
|
||||
#define RG_COREPLL_SDM_PCW_M 0x3ffffe
|
||||
#define RG_COREPLL_SDM_PCW_CHG BIT(0)
|
||||
|
||||
/* MT7531 RGMII and SGMII PLL clock */
|
||||
#define MT7531_ANA_PLLGP_CR2 0x78b0
|
||||
#define MT7531_ANA_PLLGP_CR5 0x78bc
|
||||
|
||||
/* MT7531 GPIO GROUP IOLB SMT0 Control */
|
||||
#define MT7531_SMT0_IOLB 0x7f04
|
||||
#define SMT_IOLB_5_SMI_MDC_EN BIT(5)
|
||||
|
||||
/* MT7530 GPHY MDIO MMD Registers */
|
||||
#define CORE_PLL_GROUP2 0x401
|
||||
#define RG_SYSPLL_EN_NORMAL BIT(15)
|
||||
#define RG_SYSPLL_VODEN BIT(14)
|
||||
#define RG_SYSPLL_POSDIV_S 5
|
||||
#define RG_SYSPLL_POSDIV_M 0x60
|
||||
|
||||
#define CORE_PLL_GROUP4 0x403
|
||||
#define MT7531_BYPASS_MODE BIT(4)
|
||||
#define MT7531_POWER_ON_OFF BIT(5)
|
||||
#define RG_SYSPLL_DDSFBK_EN BIT(12)
|
||||
#define RG_SYSPLL_BIAS_EN BIT(11)
|
||||
#define RG_SYSPLL_BIAS_LPF_EN BIT(10)
|
||||
|
||||
#define CORE_PLL_GROUP5 0x404
|
||||
#define RG_LCDDS_PCW_NCPO1_S 0
|
||||
#define RG_LCDDS_PCW_NCPO1_M 0xffff
|
||||
|
||||
#define CORE_PLL_GROUP6 0x405
|
||||
#define RG_LCDDS_PCW_NCPO0_S 0
|
||||
#define RG_LCDDS_PCW_NCPO0_M 0xffff
|
||||
|
||||
#define CORE_PLL_GROUP7 0x406
|
||||
#define RG_LCDDS_PWDB BIT(15)
|
||||
#define RG_LCDDS_ISO_EN BIT(13)
|
||||
#define RG_LCCDS_C_S 4
|
||||
#define RG_LCCDS_C_M 0x70
|
||||
#define RG_LCDDS_PCW_NCPO_CHG BIT(3)
|
||||
|
||||
#define CORE_PLL_GROUP10 0x409
|
||||
#define RG_LCDDS_SSC_DELTA_S 0
|
||||
#define RG_LCDDS_SSC_DELTA_M 0xfff
|
||||
|
||||
#define CORE_PLL_GROUP11 0x40a
|
||||
#define RG_LCDDS_SSC_DELTA1_S 0
|
||||
#define RG_LCDDS_SSC_DELTA1_M 0xfff
|
||||
|
||||
#define CORE_GSWPLL_GRP1 0x40d
|
||||
#define RG_GSWPLL_POSDIV_200M_S 12
|
||||
#define RG_GSWPLL_POSDIV_200M_M 0x3000
|
||||
#define RG_GSWPLL_EN_PRE BIT(11)
|
||||
#define RG_GSWPLL_FBKDIV_200M_S 0
|
||||
#define RG_GSWPLL_FBKDIV_200M_M 0xff
|
||||
|
||||
#define CORE_GSWPLL_GRP2 0x40e
|
||||
#define RG_GSWPLL_POSDIV_500M_S 8
|
||||
#define RG_GSWPLL_POSDIV_500M_M 0x300
|
||||
#define RG_GSWPLL_FBKDIV_500M_S 0
|
||||
#define RG_GSWPLL_FBKDIV_500M_M 0xff
|
||||
|
||||
#define CORE_TRGMII_GSW_CLK_CG 0x410
|
||||
#define REG_GSWCK_EN BIT(0)
|
||||
#define REG_TRGMIICK_EN BIT(1)
|
||||
|
||||
/* Extend PHY Control Register 3 */
|
||||
#define PHY_EXT_REG_14 0x14
|
||||
|
||||
/* Fields of PHY_EXT_REG_14 */
|
||||
#define PHY_EN_DOWN_SHFIT BIT(4)
|
||||
|
||||
/* Extend PHY Control Register 4 */
|
||||
#define PHY_EXT_REG_17 0x17
|
||||
|
||||
/* Fields of PHY_EXT_REG_17 */
|
||||
#define PHY_LINKDOWN_POWER_SAVING_EN BIT(4)
|
||||
|
||||
/* PHY RXADC Control Register 7 */
|
||||
#define PHY_DEV1E_REG_0C6 0x0c6
|
||||
|
||||
/* Fields of PHY_DEV1E_REG_0C6 */
|
||||
#define PHY_POWER_SAVING_S 8
|
||||
#define PHY_POWER_SAVING_M 0x300
|
||||
#define PHY_POWER_SAVING_TX 0x0
|
||||
|
||||
struct mt753x_switch_priv {
|
||||
struct mtk_eth_switch_priv epriv;
|
||||
struct mii_dev *mdio_bus;
|
||||
u32 smi_addr;
|
||||
u32 phy_base;
|
||||
u32 pmcr;
|
||||
|
||||
int (*reg_read)(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
|
||||
int (*reg_write)(struct mt753x_switch_priv *priv, u32 reg, u32 data);
|
||||
};
|
||||
|
||||
int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
|
||||
u32 *data);
|
||||
int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
|
||||
int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
|
||||
|
||||
int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data);
|
||||
int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data);
|
||||
void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set);
|
||||
|
||||
int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg);
|
||||
int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val);
|
||||
int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
||||
u16 reg);
|
||||
int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
|
||||
u16 reg, u16 val);
|
||||
|
||||
int mt7531_mdio_register(struct mt753x_switch_priv *priv);
|
||||
|
||||
void mt753x_port_isolation(struct mt753x_switch_priv *priv);
|
||||
|
||||
#endif /* _MTK_ETH_MT753X_H_ */
|
||||
160
drivers/net/mtk_eth/mt7988.c
Normal file
160
drivers/net/mtk_eth/mt7988.c
Normal file
@@ -0,0 +1,160 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 MediaTek Inc.
|
||||
*
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
* Author: Mark Lee <mark-mc.lee@mediatek.com>
|
||||
*/
|
||||
|
||||
#include <miiphy.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/io.h>
|
||||
#include "mtk_eth.h"
|
||||
#include "mt753x.h"
|
||||
|
||||
static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
|
||||
{
|
||||
*data = readl(priv->epriv.ethsys_base + GSW_BASE + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
|
||||
{
|
||||
writel(data, priv->epriv.ethsys_base + GSW_BASE + reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mt7988_phy_setting(struct mt753x_switch_priv *priv)
|
||||
{
|
||||
u16 val;
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
/* Enable HW auto downshift */
|
||||
mt7531_mii_write(priv, i, 0x1f, 0x1);
|
||||
val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
|
||||
val |= PHY_EN_DOWN_SHFIT;
|
||||
mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
|
||||
|
||||
/* PHY link down power saving enable */
|
||||
val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
|
||||
val |= PHY_LINKDOWN_POWER_SAVING_EN;
|
||||
mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
|
||||
}
|
||||
}
|
||||
|
||||
static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
u32 pmcr = FORCE_MODE_LNK;
|
||||
|
||||
if (enable)
|
||||
pmcr = priv->pmcr;
|
||||
|
||||
mt7988_reg_write(priv, PMCR_REG(6), pmcr);
|
||||
}
|
||||
|
||||
static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
u16 phy_addr, phy_val;
|
||||
u32 pmcr;
|
||||
int i;
|
||||
|
||||
priv->smi_addr = MT753X_DFL_SMI_ADDR;
|
||||
priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
|
||||
priv->reg_read = mt7988_reg_read;
|
||||
priv->reg_write = mt7988_reg_write;
|
||||
|
||||
/* Turn off PHYs */
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
||||
phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
||||
phy_val |= BMCR_PDOWN;
|
||||
mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
||||
}
|
||||
|
||||
switch (priv->epriv.phy_interface) {
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
/* Use CPU bridge instead of actual USXGMII path */
|
||||
|
||||
/* Disable GDM1 RX CRC stripping */
|
||||
/* mtk_fe_rmw(priv, 0x500, BIT(16), 0); */
|
||||
|
||||
/* Set GDM1 no drop */
|
||||
mtk_fe_rmw(priv->epriv.eth, PSE_NO_DROP_CFG_REG, 0,
|
||||
PSE_NO_DROP_GDM1);
|
||||
|
||||
/* Enable GSW CPU bridge as USXGMII */
|
||||
/* mtk_fe_rmw(priv, 0x504, BIT(31), BIT(31)); */
|
||||
|
||||
/* Enable GDM1 to GSW CPU bridge */
|
||||
mtk_gmac_rmw(priv->epriv.eth, GMAC_MAC_MISC_REG, 0, BIT(0));
|
||||
|
||||
/* XGMAC force link up */
|
||||
mtk_gmac_rmw(priv->epriv.eth, GMAC_XGMAC_STS_REG, 0,
|
||||
P1_XGMAC_FORCE_LINK);
|
||||
|
||||
/* Setup GSW CPU bridge IPG */
|
||||
mtk_gmac_rmw(priv->epriv.eth, GMAC_GSW_CFG_REG,
|
||||
GSWTX_IPG_M | GSWRX_IPG_M,
|
||||
(0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
|
||||
break;
|
||||
default:
|
||||
printf("Error: MT7988 GSW does not support %s interface\n",
|
||||
phy_string_for_interface(priv->epriv.phy_interface));
|
||||
break;
|
||||
}
|
||||
|
||||
pmcr = MT7988_FORCE_MODE |
|
||||
(IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
|
||||
MAC_MODE | MAC_TX_EN | MAC_RX_EN |
|
||||
BKOFF_EN | BACKPR_EN |
|
||||
FORCE_RX_FC | FORCE_TX_FC |
|
||||
(SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
|
||||
FORCE_LINK;
|
||||
|
||||
priv->pmcr = pmcr;
|
||||
|
||||
/* Keep MAC link down before starting eth */
|
||||
mt7988_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
|
||||
|
||||
/* Enable port isolation to block inter-port communication */
|
||||
mt753x_port_isolation(priv);
|
||||
|
||||
/* Turn on PHYs */
|
||||
for (i = 0; i < MT753X_NUM_PHYS; i++) {
|
||||
phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
|
||||
phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
|
||||
phy_val &= ~BMCR_PDOWN;
|
||||
mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
|
||||
}
|
||||
|
||||
mt7988_phy_setting(priv);
|
||||
|
||||
return mt7531_mdio_register(priv);
|
||||
}
|
||||
|
||||
static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
|
||||
{
|
||||
struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
|
||||
|
||||
mdio_unregister(priv->mdio_bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MTK_ETH_SWITCH(mt7988) = {
|
||||
.name = "mt7988",
|
||||
.desc = "MediaTek MT7988 built-in switch",
|
||||
.priv_size = sizeof(struct mt753x_switch_priv),
|
||||
.reset_wait_time = 50,
|
||||
|
||||
.setup = mt7988_setup,
|
||||
.cleanup = mt7531_cleanup,
|
||||
.mac_control = mt7988_mac_control,
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2018 MediaTek Inc.
|
||||
* Copyright (C) 2025 MediaTek Inc.
|
||||
*
|
||||
* Author: Weijie Gao <weijie.gao@mediatek.com>
|
||||
* Author: Mark Lee <mark-mc.lee@mediatek.com>
|
||||
@@ -9,9 +9,55 @@
|
||||
#ifndef _MTK_ETH_H_
|
||||
#define _MTK_ETH_H_
|
||||
|
||||
#include <linker_lists.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
struct mtk_eth_priv;
|
||||
struct mtk_eth_switch_priv;
|
||||
|
||||
/* struct mtk_soc_data - This is the structure holding all differences
|
||||
* among various plaforms
|
||||
* @caps Flags shown the extra capability for the SoC
|
||||
* @ana_rgc3: The offset for register ANA_RGC3 related to
|
||||
* sgmiisys syscon
|
||||
* @gdma_count: Number of GDMAs
|
||||
* @pdma_base: Register base of PDMA block
|
||||
* @txd_size: Tx DMA descriptor size.
|
||||
* @rxd_size: Rx DMA descriptor size.
|
||||
*/
|
||||
struct mtk_soc_data {
|
||||
u32 caps;
|
||||
u32 ana_rgc3;
|
||||
u32 gdma_count;
|
||||
u32 pdma_base;
|
||||
u32 txd_size;
|
||||
u32 rxd_size;
|
||||
};
|
||||
|
||||
struct mtk_eth_switch {
|
||||
const char *name;
|
||||
const char *desc;
|
||||
size_t priv_size;
|
||||
u32 reset_wait_time;
|
||||
|
||||
int (*detect)(struct mtk_eth_priv *priv);
|
||||
int (*setup)(struct mtk_eth_switch_priv *priv);
|
||||
int (*cleanup)(struct mtk_eth_switch_priv *priv);
|
||||
void (*mac_control)(struct mtk_eth_switch_priv *priv, bool enable);
|
||||
};
|
||||
|
||||
#define MTK_ETH_SWITCH(__name) \
|
||||
ll_entry_declare(struct mtk_eth_switch, __name, mtk_eth_switch)
|
||||
|
||||
struct mtk_eth_switch_priv {
|
||||
struct mtk_eth_priv *eth;
|
||||
const struct mtk_eth_switch *sw;
|
||||
const struct mtk_soc_data *soc;
|
||||
void *ethsys_base;
|
||||
int phy_interface;
|
||||
};
|
||||
|
||||
enum mkt_eth_capabilities {
|
||||
MTK_TRGMII_BIT,
|
||||
MTK_TRGMII_MT7621_CLK_BIT,
|
||||
@@ -36,7 +82,6 @@ enum mkt_eth_capabilities {
|
||||
|
||||
/* 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)
|
||||
@@ -59,6 +104,8 @@ enum mkt_eth_capabilities {
|
||||
|
||||
#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 */
|
||||
@@ -72,7 +119,6 @@ enum mkt_eth_capabilities {
|
||||
#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
|
||||
@@ -191,7 +237,6 @@ enum mkt_eth_capabilities {
|
||||
#define DP_DISCARD 7
|
||||
|
||||
/* GMAC Registers */
|
||||
|
||||
#define GMAC_PPSC_REG 0x0000
|
||||
#define PHY_MDC_CFG GENMASK(29, 24)
|
||||
#define MDC_TURBO BIT(20)
|
||||
@@ -272,6 +317,8 @@ enum mkt_eth_capabilities {
|
||||
#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
|
||||
@@ -288,164 +335,7 @@ enum mkt_eth_capabilities {
|
||||
#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 */
|
||||
/* MDIO Indirect Access Registers */
|
||||
#define MII_MMD_ACC_CTL_REG 0x0d
|
||||
#define MMD_CMD_S 14
|
||||
#define MMD_CMD_M 0xc000
|
||||
@@ -460,80 +350,6 @@ enum mkt_eth_capabilities {
|
||||
|
||||
#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;
|
||||
@@ -597,4 +413,17 @@ struct mtk_tx_dma_v2 {
|
||||
#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_ */
|
||||
Reference in New Issue
Block a user