]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
net: mediatek: add support for MediaTek MT7988 SoC
authorWeijie Gao <weijie.gao@mediatek.com>
Wed, 19 Jul 2023 09:17:41 +0000 (17:17 +0800)
committerTom Rini <trini@konsulko.com>
Thu, 3 Aug 2023 13:40:50 +0000 (09:40 -0400)
This patch adds support for MediaTek MT7988.

MT7988 features MediaTek NETSYS v3, including three GMACs, and two
of them supports 10Gbps USXGMII.

MT7988 embeds a MT7531 switch (not MCM) which supports accessing
internal registers through MMIO instead of MDIO.

Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
drivers/net/mtk_eth.c
drivers/net/mtk_eth.h

index e0dc180e3c1f10ef90d8407c937ca75f219777f5..d4111e73df1d61f7613cc7c5849cdeddb60a4896 100644 (file)
        (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
@@ -102,6 +113,7 @@ struct mtk_eth_priv {
        void __iomem *fe_base;
        void __iomem *gmac_base;
        void __iomem *sgmii_base;
+       void __iomem *gsw_base;
 
        struct regmap *ethsys_regmap;
 
@@ -171,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);
@@ -208,6 +225,16 @@ static void mtk_infra_rmw(struct mtk_eth_priv *priv, u32 reg, u32 clr,
        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)
@@ -342,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)
@@ -367,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)
@@ -537,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;
@@ -957,6 +995,103 @@ static int mt7531_setup(struct mtk_eth_priv *priv)
        return 0;
 }
 
+static void mt7988_phy_setting(struct mtk_eth_priv *priv)
+{
+       u16 val;
+       u32 i;
+
+       for (i = 0; i < MT753X_NUM_PHYS; i++) {
+               /* Enable HW auto downshift */
+               priv->mii_write(priv, i, 0x1f, 0x1);
+               val = priv->mii_read(priv, i, PHY_EXT_REG_14);
+               val |= PHY_EN_DOWN_SHFIT;
+               priv->mii_write(priv, i, PHY_EXT_REG_14, val);
+
+               /* PHY link down power saving enable */
+               val = priv->mii_read(priv, i, PHY_EXT_REG_17);
+               val |= PHY_LINKDOWN_POWER_SAVING_EN;
+               priv->mii_write(priv, i, PHY_EXT_REG_17, val);
+       }
+}
+
+static void mt7988_mac_control(struct mtk_eth_priv *priv, bool enable)
+{
+       u32 pmcr = FORCE_MODE_LNK;
+
+       if (enable)
+               pmcr = priv->mt753x_pmcr;
+
+       mt753x_reg_write(priv, PMCR_REG(6), pmcr);
+}
+
+static int mt7988_setup(struct mtk_eth_priv *priv)
+{
+       u16 phy_addr, phy_val;
+       u32 pmcr;
+       int i;
+
+       priv->gsw_base = regmap_get_range(priv->ethsys_regmap, 0) + GSW_BASE;
+
+       priv->mt753x_phy_base = (priv->mt753x_smi_addr + 1) &
+                               MT753X_SMI_ADDR_MASK;
+
+       /* Turn off PHYs */
+       for (i = 0; i < MT753X_NUM_PHYS; i++) {
+               phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+               phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+               phy_val |= BMCR_PDOWN;
+               priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+       }
+
+       switch (priv->phy_interface) {
+       case PHY_INTERFACE_MODE_USXGMII:
+               /* Use CPU bridge instead of actual USXGMII path */
+
+               /* Set GDM1 no drop */
+               mtk_fe_rmw(priv, PSE_NO_DROP_CFG_REG, 0, PSE_NO_DROP_GDM1);
+
+               /* Enable GDM1 to GSW CPU bridge */
+               mtk_gmac_rmw(priv, GMAC_MAC_MISC_REG, 0, BIT(0));
+
+               /* XGMAC force link up */
+               mtk_gmac_rmw(priv, GMAC_XGMAC_STS_REG, 0, P1_XGMAC_FORCE_LINK);
+
+               /* Setup GSW CPU bridge IPG */
+               mtk_gmac_rmw(priv, GMAC_GSW_CFG_REG, GSWTX_IPG_M | GSWRX_IPG_M,
+                            (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
+               break;
+       default:
+               printf("Error: MT7988 GSW does not support %s interface\n",
+                      phy_string_for_interface(priv->phy_interface));
+               break;
+       }
+
+       pmcr = MT7988_FORCE_MODE |
+              (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
+              MAC_MODE | MAC_TX_EN | MAC_RX_EN |
+              BKOFF_EN | BACKPR_EN |
+              FORCE_RX_FC | FORCE_TX_FC |
+              (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
+              FORCE_LINK;
+
+       priv->mt753x_pmcr = pmcr;
+
+       /* Keep MAC link down before starting eth */
+       mt753x_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
+
+       /* Turn on PHYs */
+       for (i = 0; i < MT753X_NUM_PHYS; i++) {
+               phy_addr = MT753X_PHY_ADDR(priv->mt753x_phy_base, i);
+               phy_val = priv->mii_read(priv, phy_addr, MII_BMCR);
+               phy_val &= ~BMCR_PDOWN;
+               priv->mii_write(priv, phy_addr, MII_BMCR, phy_val);
+       }
+
+       mt7988_phy_setting(priv);
+
+       return 0;
+}
+
 static int mt753x_switch_init(struct mtk_eth_priv *priv)
 {
        int ret;
@@ -1497,6 +1632,11 @@ static int mtk_eth_start(struct udevice *dev)
        }
 
        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);
        }
@@ -1845,6 +1985,12 @@ static int mtk_eth_of_to_plat(struct udevice *dev)
                        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;
@@ -1879,6 +2025,15 @@ 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,
@@ -1930,6 +2085,7 @@ static const struct mtk_soc_data mt7621_data = {
 };
 
 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 },
index 5e628e0cb7346456d9b292fc21f61fe7a0a1e2c1..491cac56a81a04f9576e926a045909f0a61dc1f2 100644 (file)
@@ -51,6 +51,8 @@ enum mkt_eth_capabilities {
 
 #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
@@ -59,6 +61,7 @@ enum mkt_eth_capabilities {
 #define GDMA2_BASE                     0x1500
 #define GDMA3_BASE                     0x0540
 #define GMAC_BASE                      0x10000
+#define GSW_BASE                       0x20000
 
 /* Ethernet subsystem registers */
 
@@ -117,6 +120,9 @@ enum mkt_eth_capabilities {
 #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)
 
@@ -187,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
@@ -285,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