diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/mtk_eth.c | 572 | ||||
-rw-r--r-- | drivers/net/mtk_eth.h | 69 | ||||
-rw-r--r-- | drivers/net/rtl8169.c | 22 | ||||
-rw-r--r-- | drivers/net/ti/am65-cpsw-nuss.c | 61 |
4 files changed, 684 insertions, 40 deletions
diff --git a/drivers/net/mtk_eth.c b/drivers/net/mtk_eth.c index 4c9fb266c7a..d4111e73df1 100644 --- a/drivers/net/mtk_eth.c +++ b/drivers/net/mtk_eth.c @@ -54,6 +54,16 @@ (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 | \ @@ -68,7 +78,8 @@ enum mtk_switch { SW_NONE, SW_MT7530, - SW_MT7531 + SW_MT7531, + SW_MT7988, }; /* struct mtk_soc_data - This is the structure holding all differences @@ -76,6 +87,7 @@ enum mtk_switch { * @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. @@ -83,6 +95,7 @@ enum mtk_switch { struct mtk_soc_data { u32 caps; u32 ana_rgc3; + u32 gdma_count; u32 pdma_base; u32 txd_size; u32 rxd_size; @@ -100,9 +113,17 @@ struct mtk_eth_priv { 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); @@ -123,8 +144,11 @@ struct mtk_eth_priv { 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; @@ -149,7 +173,9 @@ static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg, { u32 gdma_base; - if (no == 1) + if (no == 2) + gdma_base = GDMA3_BASE; + else if (no == 1) gdma_base = GDMA2_BASE; else gdma_base = GDMA1_BASE; @@ -157,6 +183,11 @@ static void mtk_gdma_write(struct mtk_eth_priv *priv, int no, u32 reg, 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); @@ -183,6 +214,27 @@ static void mtk_ethsys_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr, 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) @@ -195,7 +247,7 @@ static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data, (((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) + 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); @@ -207,7 +259,7 @@ static int mtk_mii_rw(struct mtk_eth_priv *priv, u8 phy, u8 reg, u16 data, return ret; } - if (cmd == MDIO_CMD_READ) { + if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) { val = mtk_gmac_read(priv, GMAC_PIAC_REG); return val & MDIO_RW_DATA_M; } @@ -317,6 +369,11 @@ 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) @@ -342,6 +399,11 @@ 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) @@ -433,7 +495,8 @@ static int mt7531_mii_ind_write(struct mtk_eth_priv *priv, u8 phy, u8 reg, MDIO_ST_C22); } -int mt7531_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, u16 reg) +static int mt7531_mmd_ind_read(struct mtk_eth_priv *priv, u8 addr, u8 devad, + u16 reg) { u8 phy_addr; int ret; @@ -511,6 +574,7 @@ static int mtk_mdio_register(struct udevice *dev) 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; @@ -613,6 +677,16 @@ static int mt7530_pad_clk_setup(struct mtk_eth_priv *priv, int mode) 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; @@ -663,11 +737,14 @@ static int mt7530_setup(struct mtk_eth_priv *priv) FORCE_DPX | FORCE_LINK; /* MT7530 Port6: Forced 1000M/FD, FC disabled */ - mt753x_reg_write(priv, PMCR_REG(6), val); + 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); @@ -823,6 +900,17 @@ static void mt7531_phy_setting(struct mtk_eth_priv *priv) } } +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; @@ -865,7 +953,7 @@ static int mt7531_setup(struct mtk_eth_priv *priv) if (!port5_sgmii) mt7531_port_rgmii_init(priv, 5); break; - case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: mt7531_port_sgmii_init(priv, 6); if (port5_sgmii) mt7531_port_sgmii_init(priv, 5); @@ -882,8 +970,11 @@ static int mt7531_setup(struct mtk_eth_priv *priv) (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX | FORCE_LINK; - mt753x_reg_write(priv, PMCR_REG(5), pmcr); - mt753x_reg_write(priv, PMCR_REG(6), pmcr); + 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++) { @@ -904,7 +995,104 @@ static int mt7531_setup(struct mtk_eth_priv *priv) return 0; } -int mt753x_switch_init(struct mtk_eth_priv *priv) +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; @@ -914,12 +1102,12 @@ int mt753x_switch_init(struct mtk_eth_priv *priv) reset_assert(&priv->rst_mcm); udelay(1000); reset_deassert(&priv->rst_mcm); - mdelay(1000); + 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(1000); + mdelay(priv->mt753x_reset_wait_time); } ret = priv->switch_init(priv); @@ -945,6 +1133,42 @@ int mt753x_switch_init(struct mtk_eth_priv *priv) 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; @@ -955,6 +1179,7 @@ static void mtk_phy_link_adjust(struct mtk_eth_priv *priv) (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) { @@ -965,6 +1190,7 @@ static void mtk_phy_link_adjust(struct mtk_eth_priv *priv) mcr |= (SPEED_100M << FORCE_SPD_S); break; case SPEED_1000: + case SPEED_2500: mcr |= (SPEED_1000M << FORCE_SPD_S); break; }; @@ -1017,7 +1243,12 @@ static int mtk_phy_start(struct mtk_eth_priv *priv) return 0; } - mtk_phy_link_adjust(priv); + if (!priv->force_mode) { + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) + mtk_xphy_link_adjust(priv); + else + mtk_phy_link_adjust(priv); + } debug("Speed: %d, %s duplex%s\n", phydev->speed, (phydev->duplex) ? "full" : "half", @@ -1045,7 +1276,31 @@ static int mtk_phy_probe(struct udevice *dev) return 0; } -static void mtk_sgmii_init(struct mtk_eth_priv *priv) +static void mtk_sgmii_an_init(struct mtk_eth_priv *priv) +{ + /* Set SGMII GEN1 speed(1G) */ + clrsetbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, + SGMSYS_SPEED_2500, 0); + + /* 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) */ setbits_le32(priv->sgmii_base + priv->soc->ana_rgc3, @@ -1069,6 +1324,112 @@ static void mtk_sgmii_init(struct mtk_eth_priv *priv) 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_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_mac_init(struct mtk_eth_priv *priv) { int i, ge_mode = 0; @@ -1080,10 +1441,19 @@ static void mtk_mac_init(struct mtk_eth_priv *priv) ge_mode = GE_MODE_RGMII; break; case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_2500BASEX: + 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); + } + ge_mode = GE_MODE_RGMII; mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, SYSCFG0_SGMII_SEL_M, SYSCFG0_SGMII_SEL(priv->gmac_id)); - mtk_sgmii_init(priv); + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII) + mtk_sgmii_an_init(priv); + else + mtk_sgmii_force_init(priv); break; case PHY_INTERFACE_MODE_MII: case PHY_INTERFACE_MODE_GMII: @@ -1117,6 +1487,7 @@ static void mtk_mac_init(struct mtk_eth_priv *priv) mcr |= SPEED_100M << FORCE_SPD_S; break; case SPEED_1000: + case SPEED_2500: mcr |= SPEED_1000M << FORCE_SPD_S; break; } @@ -1141,6 +1512,36 @@ static void mtk_mac_init(struct mtk_eth_priv *priv) } } +static void mtk_xmac_init(struct mtk_eth_priv *priv) +{ + u32 sts; + + switch (priv->phy_interface) { + case PHY_INTERFACE_MODE_USXGMII: + mtk_usxgmii_an_init(priv); + break; + default: + break; + } + + /* Set GMAC to the correct mode */ + mtk_ethsys_rmw(priv, ETHSYS_SYSCFG0_REG, + SYSCFG0_GE_MODE_M << SYSCFG0_GE_MODE_S(priv->gmac_id), + 0); + + if (priv->gmac_id == 1) { + mtk_infra_rmw(priv, TOPMISC_NETSYS_PCS_MUX, + NETSYS_PCS_MUX_MASK, MUX_G2_USXGMII_SEL); + } else if (priv->gmac_id == 2) { + sts = mtk_gmac_read(priv, XGMAC_STS(priv->gmac_id)); + sts |= XGMAC_FORCE_LINK; + mtk_gmac_write(priv, XGMAC_STS(priv->gmac_id), sts); + } + + /* Force GMAC link down */ + mtk_gmac_write(priv, GMAC_PORT_MCR(priv->gmac_id), FORCE_MODE); +} + static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) { char *pkt_base = priv->pkt_pool; @@ -1167,7 +1568,10 @@ static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) txd->txd1 = virt_to_phys(pkt_base); txd->txd2 = PDMA_TXD2_DDONE | PDMA_TXD2_LS0; - if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) + 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); @@ -1180,7 +1584,8 @@ static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) rxd->rxd1 = virt_to_phys(pkt_base); - if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) + 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); @@ -1204,7 +1609,7 @@ static void mtk_eth_fifo_init(struct mtk_eth_priv *priv) static int mtk_eth_start(struct udevice *dev) { struct mtk_eth_priv *priv = dev_get_priv(dev); - int ret; + int i, ret; /* Reset FE */ reset_assert(&priv->rst_fe); @@ -1212,21 +1617,37 @@ static int mtk_eth_start(struct udevice *dev) reset_deassert(&priv->rst_fe); mdelay(10); - if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) + 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); - if (priv->gmac_id == 0) - mtk_gdma_write(priv, 1, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); - else - mtk_gdma_write(priv, 0, GDMA_IG_CTRL_REG, GDMA_FWD_DISCARD); + 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); + } 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); @@ -1245,6 +1666,9 @@ 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); @@ -1289,7 +1713,8 @@ static int mtk_eth_send(struct udevice *dev, void *packet, int 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)) + 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); @@ -1315,7 +1740,8 @@ static int mtk_eth_recv(struct udevice *dev, int flags, uchar **packetp) return -EAGAIN; } - if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) + 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); @@ -1338,7 +1764,8 @@ static int mtk_eth_free_pkt(struct udevice *dev, uchar *packet, int length) rxd = priv->rx_ring_noc + idx * priv->soc->rxd_size; - if (MTK_HAS_CAPS(priv->soc->caps, MTK_NETSYS_V2)) + 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); @@ -1376,7 +1803,10 @@ static int mtk_eth_probe(struct udevice *dev) ARCH_DMA_MINALIGN); /* Set MAC mode */ - mtk_mac_init(priv); + if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) + mtk_xmac_init(priv); + else + mtk_mac_init(priv); /* Probe phy if switch is not specified */ if (priv->sw == SW_NONE) @@ -1428,6 +1858,19 @@ static int mtk_eth_of_to_plat(struct udevice *dev) 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) { @@ -1453,13 +1896,15 @@ static int mtk_eth_of_to_plat(struct udevice *dev) priv->duplex = ofnode_read_bool(subnode, "full-duplex"); if (priv->speed != SPEED_10 && priv->speed != SPEED_100 && - priv->speed != SPEED_1000) { + 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) { + if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII || + priv->phy_interface == PHY_INTERFACE_MODE_2500BASEX) { /* get corresponding sgmii phandle */ ret = dev_read_phandle_with_args(dev, "mediatek,sgmiisys", NULL, 0, 0, &args); @@ -1479,22 +1924,73 @@ static int mtk_eth_of_to_plat(struct udevice *dev) } priv->pn_swap = ofnode_read_bool(args.node, "pn_swap"); + } else if (priv->phy_interface == PHY_INTERFACE_MODE_USXGMII) { + /* 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; @@ -1529,17 +2025,28 @@ static int mtk_eth_of_to_plat(struct udevice *dev) 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 = MT7986_CAPS, + .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), @@ -1547,6 +2054,7 @@ static const struct mtk_soc_data mt7981_data = { static const struct mtk_soc_data mt7629_data = { .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), @@ -1554,6 +2062,7 @@ static const struct mtk_soc_data mt7629_data = { 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), @@ -1561,6 +2070,7 @@ static const struct mtk_soc_data mt7623_data = { static const struct mtk_soc_data mt7622_data = { .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), @@ -1568,12 +2078,14 @@ static const struct mtk_soc_data mt7622_data = { 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 }, diff --git a/drivers/net/mtk_eth.h b/drivers/net/mtk_eth.h index 1382ccbeb21..491cac56a81 100644 --- a/drivers/net/mtk_eth.h +++ b/drivers/net/mtk_eth.h @@ -15,35 +15,53 @@ 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, }; #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_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 MT7623_CAPS (MTK_GMAC1_TRGMII) +#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 */ @@ -56,6 +74,16 @@ enum mkt_eth_capabilities { #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 + /* SYSCFG0_GE_MODE: GE Modes */ #define GE_MODE_RGMII 0 #define GE_MODE_MII 1 @@ -69,6 +97,7 @@ enum mkt_eth_capabilities { #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 @@ -81,7 +110,19 @@ enum mkt_eth_capabilities { #define SGMSYS_GEN2_SPEED_V2 0x128 #define SGMSYS_SPEED_2500 BIT(2) +/* 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) @@ -122,6 +163,9 @@ enum mkt_eth_capabilities { #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 @@ -149,6 +193,17 @@ enum mkt_eth_capabilities { #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 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 @@ -168,6 +223,7 @@ enum mkt_eth_capabilities { #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) @@ -203,6 +259,16 @@ enum mkt_eth_capabilities { #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 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) @@ -236,6 +302,9 @@ enum mkt_eth_capabilities { 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 diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 2276a465e78..963702777c2 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -96,12 +96,12 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #define TX_TIMEOUT (6*HZ) /* write/read MMIO register. Notice: {read,write}[wl] do the necessary swapping */ -#define RTL_W8(reg, val8) writeb((val8), ioaddr + (reg)) -#define RTL_W16(reg, val16) writew((val16), ioaddr + (reg)) -#define RTL_W32(reg, val32) writel((val32), ioaddr + (reg)) -#define RTL_R8(reg) readb(ioaddr + (reg)) -#define RTL_R16(reg) readw(ioaddr + (reg)) -#define RTL_R32(reg) readl(ioaddr + (reg)) +#define RTL_W8(reg, val8) writeb((val8), (void *)(ioaddr + (reg))) +#define RTL_W16(reg, val16) writew((val16), (void *)(ioaddr + (reg))) +#define RTL_W32(reg, val32) writel((val32), (void *)(ioaddr + (reg))) +#define RTL_R8(reg) readb((void *)(ioaddr + (reg))) +#define RTL_R16(reg) readw((void *)(ioaddr + (reg))) +#define RTL_R32(reg) readl((void *)(ioaddr + (reg))) #define bus_to_phys(a) pci_mem_to_phys((pci_dev_t)(unsigned long)dev->priv, \ (pci_addr_t)(unsigned long)a) @@ -311,10 +311,12 @@ static unsigned char rxdata[RX_BUF_LEN]; * * This can be fixed by defining CONFIG_SYS_NONCACHED_MEMORY which will cause * the driver to allocate descriptors from a pool of non-cached memory. + * + * Hardware maintain D-cache coherency in RISC-V architecture. */ #if RTL8169_DESC_SIZE < ARCH_DMA_MINALIGN #if !defined(CONFIG_SYS_NONCACHED_MEMORY) && \ - !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) + !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) && !defined(CONFIG_X86) && !defined(CONFIG_RISCV) #warning cache-line size is larger than descriptor size #endif #endif @@ -351,10 +353,11 @@ static const unsigned int rtl8169_rx_config = (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift); static struct pci_device_id supported[] = { + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125) }, + { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8161) }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167) }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168) }, { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169) }, - { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8125) }, {} }; @@ -1049,8 +1052,9 @@ static int rtl8169_eth_probe(struct udevice *dev) int ret; switch (pplat->device) { - case 0x8168: case 0x8125: + case 0x8161: + case 0x8168: region = 2; break; default: diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c index 51a8167d14a..f4e58093805 100644 --- a/drivers/net/ti/am65-cpsw-nuss.c +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -9,6 +9,7 @@ #include <common.h> #include <malloc.h> #include <asm/cache.h> +#include <asm/gpio.h> #include <asm/io.h> #include <asm/processor.h> #include <clk.h> @@ -26,6 +27,7 @@ #include <soc.h> #include <syscon.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/soc/ti/ti-udma.h> #include "cpsw_mdio.h" @@ -57,6 +59,12 @@ #define AM65_CPSW_PN_REG_SA_L 0x308 #define AM65_CPSW_PN_REG_SA_H 0x30c +#define AM65_CPSW_SGMII_CONTROL_REG 0x010 +#define AM65_CPSW_SGMII_MR_ADV_ABILITY_REG 0x018 +#define AM65_CPSW_SGMII_CONTROL_MR_AN_ENABLE BIT(0) + +#define ADVERTISE_SGMII 0x1 + #define AM65_CPSW_ALE_CTL_REG 0x8 #define AM65_CPSW_ALE_CTL_REG_ENABLE BIT(31) #define AM65_CPSW_ALE_CTL_REG_RESET_TBL BIT(30) @@ -90,8 +98,11 @@ #define AM65_CPSW_CPPI_PKT_TYPE 0x7 +#define DEFAULT_GPIO_RESET_DELAY 10 + struct am65_cpsw_port { fdt_addr_t port_base; + fdt_addr_t port_sgmii_base; fdt_addr_t macsl_base; bool disabled; u32 mac_control; @@ -113,6 +124,10 @@ struct am65_cpsw_common { struct mii_dev *bus; u32 bus_freq; + struct gpio_desc mdio_gpio_reset; + u32 reset_delay_us; + u32 reset_post_delay_us; + struct dma dma_tx; struct dma dma_rx; u32 rx_next; @@ -204,6 +219,8 @@ static int am65_cpsw_update_link(struct am65_cpsw_priv *priv) mac_control |= AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX; if (phy->speed == 100) mac_control |= AM65_CPSW_MACSL_CTL_REG_IFCTL_A; + if (phy->interface == PHY_INTERFACE_MODE_SGMII) + mac_control |= AM65_CPSW_MACSL_CTL_EXT_EN; } if (mac_control == port->mac_control) @@ -229,6 +246,7 @@ out: #define AM65_GMII_SEL_MODE_MII 0 #define AM65_GMII_SEL_MODE_RMII 1 #define AM65_GMII_SEL_MODE_RGMII 2 +#define AM65_GMII_SEL_MODE_SGMII 3 #define AM65_GMII_SEL_RGMII_IDMODE BIT(4) @@ -280,6 +298,10 @@ static int am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, rgmii_id = true; break; + case PHY_INTERFACE_MODE_SGMII: + mode = AM65_GMII_SEL_MODE_SGMII; + break; + default: dev_warn(dev, "Unsupported PHY mode: %u. Defaulting to MII.\n", @@ -420,6 +442,13 @@ static int am65_cpsw_start(struct udevice *dev) goto err_dis_rx; } + if (priv->phydev->interface == PHY_INTERFACE_MODE_SGMII) { + writel(ADVERTISE_SGMII, + port->port_sgmii_base + AM65_CPSW_SGMII_MR_ADV_ABILITY_REG); + writel(AM65_CPSW_SGMII_CONTROL_MR_AN_ENABLE, + port->port_sgmii_base + AM65_CPSW_SGMII_CONTROL_REG); + } + ret = phy_startup(priv->phydev); if (ret) { dev_err(dev, "phy_startup failed\n"); @@ -658,6 +687,16 @@ static int am65_cpsw_mdio_init(struct udevice *dev) if (!priv->has_phy || cpsw_common->bus) return 0; + if (IS_ENABLED(CONFIG_DM_GPIO)) { + if (dm_gpio_is_valid(&cpsw_common->mdio_gpio_reset)) { + dm_gpio_set_value(&cpsw_common->mdio_gpio_reset, 1); + udelay(cpsw_common->reset_delay_us); + dm_gpio_set_value(&cpsw_common->mdio_gpio_reset, 0); + if (cpsw_common->reset_post_delay_us > 0) + udelay(cpsw_common->reset_post_delay_us); + } + } + ret = am65_cpsw_mdio_setup(dev); if (ret) return ret; @@ -797,7 +836,7 @@ out: static int am65_cpsw_probe_nuss(struct udevice *dev) { struct am65_cpsw_common *cpsw_common = dev_get_priv(dev); - ofnode ports_np, node; + ofnode ports_np, node, mdio_np; int ret, i; struct udevice *port_dev; @@ -824,6 +863,24 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) AM65_CPSW_CPSW_NU_ALE_BASE; cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE; + if (IS_ENABLED(CONFIG_DM_GPIO)) { + /* get bus level PHY reset GPIO details */ + mdio_np = dev_read_subnode(dev, "mdio"); + if (!ofnode_valid(mdio_np)) { + ret = -ENOENT; + goto out; + } + + cpsw_common->reset_delay_us = ofnode_read_u32_default(mdio_np, "reset-delay-us", + DEFAULT_GPIO_RESET_DELAY); + cpsw_common->reset_post_delay_us = ofnode_read_u32_default(mdio_np, + "reset-post-delay-us", + 0); + ret = gpio_request_by_name_nodev(mdio_np, "reset-gpios", 0, + &cpsw_common->mdio_gpio_reset, + GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); + } + ports_np = dev_read_subnode(dev, "ethernet-ports"); if (!ofnode_valid(ports_np)) { ret = -ENOENT; @@ -872,6 +929,8 @@ static int am65_cpsw_probe_nuss(struct udevice *dev) port->port_base = cpsw_common->cpsw_base + AM65_CPSW_CPSW_NU_PORTS_OFFSET + (i * AM65_CPSW_CPSW_NU_PORTS_OFFSET); + port->port_sgmii_base = cpsw_common->ss_base + + (i * AM65_CPSW_SGMII_BASE); port->macsl_base = port->port_base + AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET; } |