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