blob: cdd52f3ff1b0530fa45c30f5d6ccdbb8781b0563 [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 <errno.h>
10#include <time.h>
11#include "mtk_eth.h"
12#include "mt753x.h"
13
14/*
15 * MT753x Internal Register Address Bits
16 * -------------------------------------------------------------------
17 * | 15 14 13 12 11 10 9 8 7 6 | 5 4 3 2 | 1 0 |
18 * |----------------------------------------|---------------|--------|
19 * | Page Address | Reg Address | Unused |
20 * -------------------------------------------------------------------
21 */
22
23int __mt753x_mdio_reg_read(struct mtk_eth_priv *priv, u32 smi_addr, u32 reg,
24 u32 *data)
25{
26 int ret, low_word, high_word;
27
28 /* Write page address */
29 ret = mtk_mii_write(priv, smi_addr, 0x1f, reg >> 6);
30 if (ret)
31 return ret;
32
33 /* Read low word */
34 low_word = mtk_mii_read(priv, smi_addr, (reg >> 2) & 0xf);
35 if (low_word < 0)
36 return low_word;
37
38 /* Read high word */
39 high_word = mtk_mii_read(priv, smi_addr, 0x10);
40 if (high_word < 0)
41 return high_word;
42
43 if (data)
44 *data = ((u32)high_word << 16) | (low_word & 0xffff);
45
46 return 0;
47}
48
49int mt753x_mdio_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
50{
51 return __mt753x_mdio_reg_read(priv->epriv.eth, priv->smi_addr, reg,
52 data);
53}
54
55int mt753x_mdio_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
56{
57 int ret;
58
59 /* Write page address */
60 ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x1f, reg >> 6);
61 if (ret)
62 return ret;
63
64 /* Write low word */
65 ret = mtk_mii_write(priv->epriv.eth, priv->smi_addr, (reg >> 2) & 0xf,
66 data & 0xffff);
67 if (ret)
68 return ret;
69
70 /* Write high word */
71 return mtk_mii_write(priv->epriv.eth, priv->smi_addr, 0x10, data >> 16);
72}
73
74int mt753x_reg_read(struct mt753x_switch_priv *priv, u32 reg, u32 *data)
75{
76 return priv->reg_read(priv, reg, data);
77}
78
79int mt753x_reg_write(struct mt753x_switch_priv *priv, u32 reg, u32 data)
80{
81 return priv->reg_write(priv, reg, data);
82}
83
84void mt753x_reg_rmw(struct mt753x_switch_priv *priv, u32 reg, u32 clr, u32 set)
85{
86 u32 val;
87
88 priv->reg_read(priv, reg, &val);
89 val &= ~clr;
90 val |= set;
91 priv->reg_write(priv, reg, val);
92}
93
94/* Indirect MDIO clause 22/45 access */
95static int mt7531_mii_rw(struct mt753x_switch_priv *priv, int phy, int reg,
96 u16 data, u32 cmd, u32 st)
97{
98 u32 val, timeout_ms;
99 ulong timeout;
100 int ret = 0;
101
102 val = (st << MDIO_ST_S) |
103 ((cmd << MDIO_CMD_S) & MDIO_CMD_M) |
104 ((phy << MDIO_PHY_ADDR_S) & MDIO_PHY_ADDR_M) |
105 ((reg << MDIO_REG_ADDR_S) & MDIO_REG_ADDR_M);
106
107 if (cmd == MDIO_CMD_WRITE || cmd == MDIO_CMD_ADDR)
108 val |= data & MDIO_RW_DATA_M;
109
110 mt753x_reg_write(priv, MT7531_PHY_IAC, val | PHY_ACS_ST);
111
112 timeout_ms = 100;
113 timeout = get_timer(0);
114 while (1) {
115 mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
116
117 if ((val & PHY_ACS_ST) == 0)
118 break;
119
120 if (get_timer(timeout) > timeout_ms)
121 return -ETIMEDOUT;
122 }
123
124 if (cmd == MDIO_CMD_READ || cmd == MDIO_CMD_READ_C45) {
125 mt753x_reg_read(priv, MT7531_PHY_IAC, &val);
126 ret = val & MDIO_RW_DATA_M;
127 }
128
129 return ret;
130}
131
132int mt7531_mii_read(struct mt753x_switch_priv *priv, u8 phy, u8 reg)
133{
134 u8 phy_addr;
135
136 if (phy >= MT753X_NUM_PHYS)
137 return -EINVAL;
138
139 phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
140
141 return mt7531_mii_rw(priv, phy_addr, reg, 0, MDIO_CMD_READ,
142 MDIO_ST_C22);
143}
144
145int mt7531_mii_write(struct mt753x_switch_priv *priv, u8 phy, u8 reg, u16 val)
146{
147 u8 phy_addr;
148
149 if (phy >= MT753X_NUM_PHYS)
150 return -EINVAL;
151
152 phy_addr = MT753X_PHY_ADDR(priv->phy_base, phy);
153
154 return mt7531_mii_rw(priv, phy_addr, reg, val, MDIO_CMD_WRITE,
155 MDIO_ST_C22);
156}
157
158int mt7531_mmd_read(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
159 u16 reg)
160{
161 u8 phy_addr;
162 int ret;
163
164 if (addr >= MT753X_NUM_PHYS)
165 return -EINVAL;
166
167 phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
168
169 ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
170 MDIO_ST_C45);
171 if (ret)
172 return ret;
173
174 return mt7531_mii_rw(priv, phy_addr, devad, 0, MDIO_CMD_READ_C45,
175 MDIO_ST_C45);
176}
177
178int mt7531_mmd_write(struct mt753x_switch_priv *priv, u8 addr, u8 devad,
179 u16 reg, u16 val)
180{
181 u8 phy_addr;
182 int ret;
183
184 if (addr >= MT753X_NUM_PHYS)
185 return 0;
186
187 phy_addr = MT753X_PHY_ADDR(priv->phy_base, addr);
188
189 ret = mt7531_mii_rw(priv, phy_addr, devad, reg, MDIO_CMD_ADDR,
190 MDIO_ST_C45);
191 if (ret)
192 return ret;
193
194 return mt7531_mii_rw(priv, phy_addr, devad, val, MDIO_CMD_WRITE,
195 MDIO_ST_C45);
196}
197
198static int mt7531_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
199{
200 struct mt753x_switch_priv *priv = bus->priv;
201
202 if (devad < 0)
203 return mt7531_mii_read(priv, addr, reg);
204
205 return mt7531_mmd_read(priv, addr, devad, reg);
206}
207
208static int mt7531_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
209 u16 val)
210{
211 struct mt753x_switch_priv *priv = bus->priv;
212
213 if (devad < 0)
214 return mt7531_mii_write(priv, addr, reg, val);
215
216 return mt7531_mmd_write(priv, addr, devad, reg, val);
217}
218
219int mt7531_mdio_register(struct mt753x_switch_priv *priv)
220{
221 struct mii_dev *mdio_bus = mdio_alloc();
222 int ret;
223
224 if (!mdio_bus)
225 return -ENOMEM;
226
227 mdio_bus->read = mt7531_mdio_read;
228 mdio_bus->write = mt7531_mdio_write;
229 snprintf(mdio_bus->name, sizeof(mdio_bus->name), priv->epriv.sw->name);
230
231 mdio_bus->priv = priv;
232
233 ret = mdio_register(mdio_bus);
234 if (ret) {
235 mdio_free(mdio_bus);
236 return ret;
237 }
238
239 priv->mdio_bus = mdio_bus;
240
241 return 0;
242}
243
244void mt753x_port_isolation(struct mt753x_switch_priv *priv)
245{
246 u32 i;
247
248 for (i = 0; i < MT753X_NUM_PORTS; i++) {
249 /* Set port matrix mode */
250 if (i != 6)
251 mt753x_reg_write(priv, PCR_REG(i),
252 (0x40 << PORT_MATRIX_S));
253 else
254 mt753x_reg_write(priv, PCR_REG(i),
255 (0x3f << PORT_MATRIX_S));
256
257 /* Set port mode to user port */
258 mt753x_reg_write(priv, PVC_REG(i),
259 (0x8100 << STAG_VPID_S) |
260 (VLAN_ATTR_USER << VLAN_ATTR_S));
261 }
262}