1 /*
2 * Copyright (c) 2006-2024 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-10-08 zhujiale the first version
9 */
10 #include <rtthread.h>
11 #include <drivers/phy.h>
12 #include "general_phy.h"
13 #define DBG_TAG "rtdm.phy"
14 #define DBG_LVL DBG_INFO
15 #include <rtdbg.h>
16
__genphy_set_adv(int adv,int advertise)17 static int __genphy_set_adv(int adv,int advertise)
18 {
19 adv &= ~(RT_ADVERTISE_ALL | RT_ADVERTISE_100BASE4 | RT_ADVERTISE_PAUSE_CAP |
20 RT_ADVERTISE_PAUSE_ASYM);
21 if (advertise & RT_ADVERTISED__10baseT_Half)
22 adv |= RT_ADVERTISE_10HALF;
23 if (advertise & RT_ADVERTISED__10baseT_Full)
24 adv |= RT_ADVERTISE_10FULL;
25 if (advertise & RT_ADVERTISED__100baseT_Half)
26 adv |= RT_ADVERTISE_100HALF;
27 if (advertise & RT_ADVERTISED__100baseT_Full)
28 adv |= RT_ADVERTISE_100FULL;
29 if (advertise & RT_ADVERTISED__Pause)
30 adv |= RT_ADVERTISE_PAUSE_CAP;
31 if (advertise & RT_ADVERTISED__Asym_Pause)
32 adv |= RT_ADVERTISE_PAUSE_ASYM;
33 if (advertise & RT_ADVERTISED__1000baseX_Half)
34 adv |= RT_ADVERTISE_1000XHALF;
35 if (advertise & RT_ADVERTISED__1000baseX_Full)
36 adv |= RT_ADVERTISE_1000XFULL;
37
38 return adv;
39 }
__genphy_config_advert(struct rt_phy_device * phydev)40 static int __genphy_config_advert(struct rt_phy_device *phydev)
41 {
42 rt_uint32_t advertise;
43 int oldadv, adv, bmsr;
44 int err, changed = 0;
45
46 phydev->advertising &= phydev->supported;
47 advertise = phydev->advertising;
48
49 adv = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ADVERTISE);
50 oldadv = adv;
51
52 if (adv < 0)
53 return adv;
54
55 adv = __genphy_set_adv(adv, advertise);
56
57 if (adv != oldadv)
58 {
59 err = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ADVERTISE, adv);
60
61 if (err < 0)
62 return err;
63 changed = 1;
64 }
65
66 bmsr = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
67 if (bmsr < 0)
68 return bmsr;
69
70 if (!(bmsr & RT_BMSR_ESTATEN))
71 return changed;
72
73 adv = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_CTRL1000);
74 oldadv = adv;
75
76 if (adv < 0)
77 return adv;
78
79 adv &= ~(RT_ADVERTISE_1000FULL | RT_ADVERTISE_1000HALF);
80
81 if (phydev->supported & (RT_SUPPORTED_1000baseT_Half |
82 RT_SUPPORTED_1000baseT_Full))
83 {
84 if (advertise & RT_SUPPORTED_1000baseT_Half)
85 adv |= RT_ADVERTISE_1000HALF;
86 if (advertise & RT_SUPPORTED_1000baseT_Full)
87 adv |= RT_ADVERTISE_1000FULL;
88 }
89
90 if (adv != oldadv)
91 changed = 1;
92
93 err = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_CTRL1000, adv);
94 if (err < 0)
95 return err;
96
97 return changed;
98 }
99
__genphy_restart_aneg(struct rt_phy_device * phydev)100 int __genphy_restart_aneg(struct rt_phy_device *phydev)
101 {
102 int ctl;
103
104 ctl = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR);
105
106 if (ctl < 0)
107 return ctl;
108
109 ctl |= (RT_BMCR_ANENABLE | RT_BMCR_ANRESTART);
110
111 ctl &= ~(RT_BMCR_ISOLATE);
112
113 ctl = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR, ctl);
114
115 return ctl;
116 }
117
rt_genphy_config_aneg(struct rt_phy_device * phydev)118 int rt_genphy_config_aneg(struct rt_phy_device *phydev)
119 {
120 int result;
121 int err;
122 int ctl = RT_BMCR_ANRESTART;
123 if (phydev->autoneg != AUTONEG_ENABLE)
124 {
125 phydev->pause = 0;
126
127 if (phydev->speed == SPEED_1000)
128 ctl |= RT_BMCR_SPEED1000;
129 else if (phydev->speed == SPEED_100)
130 ctl |= RT_BMCR_SPEED100;
131
132 if (phydev->duplex == DUPLEX_FULL)
133 ctl |= RT_BMCR_FULLDPLX;
134
135 err = rt_phy_write(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR, ctl);
136
137 return err;
138 }
139
140 result = __genphy_config_advert(phydev);
141
142 if (result < 0)
143 return result;
144
145 if (result == 0)
146 {
147 int ctl = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR);
148
149 if (ctl < 0)
150 return ctl;
151
152 if (!(ctl & RT_BMCR_ANENABLE) || (ctl & RT_BMCR_ISOLATE))
153 result = 1;
154 }
155
156 if (result > 0)
157 result = __genphy_restart_aneg(phydev);
158
159 return result;
160 }
161
rt_genphy_update_link(struct rt_phy_device * phydev)162 int rt_genphy_update_link(struct rt_phy_device *phydev)
163 {
164 unsigned int mii_reg;
165
166 mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
167
168 if (phydev->link && mii_reg & RT_BMSR_LSTATUS)
169 return 0;
170
171 if ((phydev->autoneg == AUTONEG_ENABLE) &&
172 !(mii_reg & RT_BMSR_ANEGCOMPLETE))
173 {
174 int i = 0;
175 rt_kprintf("Waiting for PHY auto negotiation to complete");
176 while (!(mii_reg & RT_BMSR_ANEGCOMPLETE))
177 {
178
179 if (i > (RT_PHY_ANEG_TIMEOUT))
180 {
181 LOG_E(" TIMEOUT !\n");
182 phydev->link = 0;
183 return -ETIMEDOUT;
184 }
185
186 mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
187
188 rt_thread_delay(100);
189 }
190 LOG_D(" done\n");
191 phydev->link = 1;
192 } else {
193 mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
194
195 if (mii_reg & RT_BMSR_LSTATUS)
196 phydev->link = 1;
197 else
198 phydev->link = 0;
199 }
200
201 return 0;
202 }
203
__genphy_auto_neg(struct rt_phy_device * phydev,int mii_reg)204 static void __genphy_auto_neg(struct rt_phy_device *phydev,int mii_reg)
205 {
206 rt_uint32_t lpa = 0;
207 int gblpa = 0;
208 rt_uint32_t estatus = 0;
209
210 if (phydev->supported & (RT_SUPPORTED_1000baseT_Full |
211 RT_SUPPORTED_1000baseT_Half))
212 {
213
214 gblpa = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_STAT1000);
215 if (gblpa < 0)
216 {
217 LOG_D("Could not read RT_MII_STAT1000. Ignoring gigabit capability\n");
218 gblpa = 0;
219 }
220 gblpa &= rt_phy_read(phydev,
221 RT_MDIO_DEVAD_NONE, RT_MII_CTRL1000) << 2;
222 }
223
224 phydev->speed = SPEED_10;
225 phydev->duplex = DUPLEX_HALF;
226
227 if (gblpa & (RT_PHY_1000BTSR_1000FD | RT_PHY_1000BTSR_1000HD))
228 {
229 phydev->speed = SPEED_1000;
230
231 if (gblpa & RT_PHY_1000BTSR_1000FD)
232 phydev->duplex = DUPLEX_FULL;
233
234 return ;
235 }
236
237 lpa = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ADVERTISE);
238 lpa &= rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_LPA);
239
240 if (lpa & (RT_LINK_PARTNER__100FULL | RT_LINK_PARTNER__100HALF))
241 {
242 phydev->speed = SPEED_100;
243
244 if (lpa & RT_LINK_PARTNER__100FULL)
245 phydev->duplex = DUPLEX_FULL;
246
247 } else if (lpa & RT_LINK_PARTNER__10FULL)
248 {
249 phydev->duplex = DUPLEX_FULL;
250 }
251
252 if ((mii_reg & RT_BMSR_ESTATEN) && !(mii_reg & RT_BMSR_ERCAP))
253 estatus = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE,
254 RT_MII_ESTATUS);
255
256 if (estatus & (RT_SUPORT_1000B_XFULL | RT_SUPORT_1000B_XHALF |
257 RT_SUPORT_1000B_TFULL | RT_SUPORT_1000B_THALF))
258 {
259 phydev->speed = SPEED_1000;
260 if (estatus & (RT_SUPORT_1000B_XFULL | RT_SUPORT_1000B_TFULL))
261 phydev->duplex = DUPLEX_FULL;
262 }
263 }
rt_genphy_parse_link(struct rt_phy_device * phydev)264 int rt_genphy_parse_link(struct rt_phy_device *phydev)
265 {
266 int mii_reg = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
267
268 if (phydev->autoneg == AUTONEG_ENABLE)
269 {
270 __genphy_auto_neg(phydev, mii_reg);
271 } else {
272 rt_uint32_t bmcr = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMCR);
273
274 phydev->speed = SPEED_10;
275 phydev->duplex = DUPLEX_HALF;
276
277 if (bmcr & RT_BMCR_FULLDPLX)
278 phydev->duplex = DUPLEX_FULL;
279
280 if (bmcr & RT_BMCR_SPEED1000)
281 phydev->speed = SPEED_1000;
282 else if (bmcr & RT_BMCR_SPEED100)
283 phydev->speed = SPEED_100;
284 }
285
286 return 0;
287 }
288
rt_genphy_config(struct rt_phy_device * phydev)289 int rt_genphy_config(struct rt_phy_device *phydev)
290 {
291 int val;
292 rt_uint32_t features;
293
294 features = (RT_SUPPORTED_TP | RT_SUPPORTED_MII
295 | RT_SUPPORTED_AUI | RT_SUPPORTED_FIBRE |
296 RT_SUPPORTED_BNC);
297
298 val = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_BMSR);
299
300 if (val < 0)
301 return val;
302
303 if (val & RT_BMSR_ANEGCAPABLE)
304 features |= RT_SUPPORTED_Autoneg;
305
306 if (val & RT_BMSR_100FULL)
307 features |= RT_SUPPORTED_100baseT_Full;
308 if (val & RT_BMSR_100HALF)
309 features |= RT_SUPPORTED_100baseT_Half;
310 if (val & RT_BMSR_10FULL)
311 features |= RT_SUPPORTED_10baseT_Full;
312 if (val & RT_BMSR_10HALF)
313 features |= RT_SUPPORTED_10baseT_Half;
314
315 if (val & RT_BMSR_ESTATEN)
316 {
317 val = rt_phy_read(phydev, RT_MDIO_DEVAD_NONE, RT_MII_ESTATUS);
318
319 if (val < 0)
320 return val;
321
322 if (val & RT_SUPORT_1000B_TFULL)
323 features |= RT_SUPPORTED_1000baseT_Full;
324 if (val & RT_SUPORT_1000B_THALF)
325 features |= RT_SUPPORTED_1000baseT_Half;
326 if (val & RT_SUPORT_1000B_XFULL)
327 features |= RT_SUPPORTED_1000baseX_Full;
328 if (val & RT_SUPORT_1000B_XHALF)
329 features |= RT_SUPPORTED_1000baseX_Half;
330 }
331
332 phydev->supported &= features;
333 phydev->advertising &= features;
334
335 rt_genphy_config_aneg(phydev);
336
337 return 0;
338 }
339
rt_genphy_startup(struct rt_phy_device * phydev)340 int rt_genphy_startup(struct rt_phy_device *phydev)
341 {
342 int ret;
343
344 ret = rt_genphy_update_link(phydev);
345 if (ret)
346 return ret;
347
348 return rt_genphy_parse_link(phydev);
349 }
350