blob: a416d87840c048471c9ecd14ba0736c258a494ae [file] [log] [blame]
developer29d9d9f2025-01-10 16:41:13 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2025 MediaTek Inc.
4 *
5 * Author: Weijie Gao <weijie.gao@mediatek.com>
6 * Author: Mark Lee <mark-mc.lee@mediatek.com>
7 */
8
9#include <miiphy.h>
10#include <linux/delay.h>
11#include <linux/mdio.h>
12#include <linux/mii.h>
13#include <linux/io.h>
14#include "mtk_eth.h"
15#include "mt753x.h"
16
17static int mt7988_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
18{
19 *data = readl(priv->epriv.ethsys_base + GSW_BASE + reg);
20
21 return 0;
22}
23
24static int mt7988_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
25{
26 writel(data, priv->epriv.ethsys_base + GSW_BASE + reg);
27
28 return 0;
29}
30
31static void mt7988_phy_setting(struct mt753x_switch_priv *priv)
32{
33 u16 val;
34 u32 i;
35
36 for (i = 0; i < MT753X_NUM_PHYS; i++) {
37 /* Enable HW auto downshift */
38 mt7531_mii_write(priv, i, 0x1f, 0x1);
39 val = mt7531_mii_read(priv, i, PHY_EXT_REG_14);
40 val |= PHY_EN_DOWN_SHFIT;
41 mt7531_mii_write(priv, i, PHY_EXT_REG_14, val);
42
43 /* PHY link down power saving enable */
44 val = mt7531_mii_read(priv, i, PHY_EXT_REG_17);
45 val |= PHY_LINKDOWN_POWER_SAVING_EN;
46 mt7531_mii_write(priv, i, PHY_EXT_REG_17, val);
47 }
48}
49
50static void mt7988_mac_control(struct mtk_eth_switch_priv *swpriv, bool enable)
51{
52 struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
53 u32 pmcr = FORCE_MODE_LNK;
54
55 if (enable)
56 pmcr = priv->pmcr;
57
58 mt7988_reg_write(priv, PMCR_REG(6), pmcr);
59}
60
61static int mt7988_setup(struct mtk_eth_switch_priv *swpriv)
62{
63 struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
64 u16 phy_addr, phy_val;
65 u32 pmcr;
66 int i;
67
68 priv->smi_addr = MT753X_DFL_SMI_ADDR;
69 priv->phy_base = (priv->smi_addr + 1) & MT753X_SMI_ADDR_MASK;
70 priv->reg_read = mt7988_reg_read;
71 priv->reg_write = mt7988_reg_write;
72
73 /* Turn off PHYs */
74 for (i = 0; i < MT753X_NUM_PHYS; i++) {
75 phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
76 phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
77 phy_val |= BMCR_PDOWN;
78 mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
79 }
80
81 switch (priv->epriv.phy_interface) {
82 case PHY_INTERFACE_MODE_USXGMII:
83 /* Use CPU bridge instead of actual USXGMII path */
84
85 /* Disable GDM1 RX CRC stripping */
86 /* mtk_fe_rmw(priv, 0x500, BIT(16), 0); */
87
88 /* Set GDM1 no drop */
89 mtk_fe_rmw(priv->epriv.eth, PSE_NO_DROP_CFG_REG, 0,
90 PSE_NO_DROP_GDM1);
91
92 /* Enable GSW CPU bridge as USXGMII */
93 /* mtk_fe_rmw(priv, 0x504, BIT(31), BIT(31)); */
94
95 /* Enable GDM1 to GSW CPU bridge */
96 mtk_gmac_rmw(priv->epriv.eth, GMAC_MAC_MISC_REG, 0, BIT(0));
97
98 /* XGMAC force link up */
99 mtk_gmac_rmw(priv->epriv.eth, GMAC_XGMAC_STS_REG, 0,
100 P1_XGMAC_FORCE_LINK);
101
102 /* Setup GSW CPU bridge IPG */
103 mtk_gmac_rmw(priv->epriv.eth, GMAC_GSW_CFG_REG,
104 GSWTX_IPG_M | GSWRX_IPG_M,
105 (0xB << GSWTX_IPG_S) | (0xB << GSWRX_IPG_S));
106 break;
107 default:
108 printf("Error: MT7988 GSW does not support %s interface\n",
109 phy_string_for_interface(priv->epriv.phy_interface));
110 break;
111 }
112
113 pmcr = MT7988_FORCE_MODE |
114 (IPG_96BIT_WITH_SHORT_IPG << IPG_CFG_S) |
115 MAC_MODE | MAC_TX_EN | MAC_RX_EN |
116 BKOFF_EN | BACKPR_EN |
117 FORCE_RX_FC | FORCE_TX_FC |
118 (SPEED_1000M << FORCE_SPD_S) | FORCE_DPX |
119 FORCE_LINK;
120
121 priv->pmcr = pmcr;
122
123 /* Keep MAC link down before starting eth */
124 mt7988_reg_write(priv, PMCR_REG(6), FORCE_MODE_LNK);
125
126 /* Enable port isolation to block inter-port communication */
127 mt753x_port_isolation(priv);
128
129 /* Turn on PHYs */
130 for (i = 0; i < MT753X_NUM_PHYS; i++) {
131 phy_addr = MT753X_PHY_ADDR(priv->phy_base, i);
132 phy_val = mt7531_mii_read(priv, phy_addr, MII_BMCR);
133 phy_val &= ~BMCR_PDOWN;
134 mt7531_mii_write(priv, phy_addr, MII_BMCR, phy_val);
135 }
136
137 mt7988_phy_setting(priv);
138
139 return mt7531_mdio_register(priv);
140}
141
142static int mt7531_cleanup(struct mtk_eth_switch_priv *swpriv)
143{
144 struct mt753x_switch_priv *priv = (struct mt753x_switch_priv *)swpriv;
145
146 mdio_unregister(priv->mdio_bus);
147
148 return 0;
149}
150
151MTK_ETH_SWITCH(mt7988) = {
152 .name = "mt7988",
153 .desc = "MediaTek MT7988 built-in switch",
154 .priv_size = sizeof(struct mt753x_switch_priv),
155 .reset_wait_time = 50,
156
157 .setup = mt7988_setup,
158 .cleanup = mt7531_cleanup,
159 .mac_control = mt7988_mac_control,
160};