mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-08-14 03:06:59 +02:00
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>
161 lines
4.1 KiB
C
161 lines
4.1 KiB
C
// 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,
|
|
};
|