1 /*
2  * Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <rtthread.h>
17 
18 #include "cvi_eth_phy.h"
19 
20 #define CSI_ETH_AUTONEG_DISABLE         (0)     ///< Disable auto-negotiation
21 #define CSI_ETH_AUTONEG_ENABLE          (1)     ///< Enable auto-negotiation
22 
23 #define CONFIG_ETH_PHY_NUM 2
24 
25 eth_phy_priv_t  phy_priv_list[CONFIG_ETH_PHY_NUM];
26 
27 extern eth_phy_dev_t cv181x_device;
28 
29 /* registered phy devices */
30 static eth_phy_dev_t *const eth_phy_devices[] = {
31     &cv181x_device,
32     NULL /* Must be the last item */
33 };
34 
eth_phy_read(eth_phy_priv_t * priv,uint8_t phy_addr,uint8_t reg_addr,uint16_t * data)35 int32_t eth_phy_read(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
36 {
37     RT_ASSERT(priv);
38     RT_ASSERT(priv->phy_read);
39     return priv->phy_read(phy_addr, reg_addr, data);
40 }
41 
eth_phy_write(eth_phy_priv_t * priv,uint8_t phy_addr,uint8_t reg_addr,uint16_t data)42 int32_t eth_phy_write(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
43 {
44     RT_ASSERT(priv);
45     RT_ASSERT(priv->phy_write);
46     return priv->phy_write(phy_addr, reg_addr, data);
47 }
48 
eth_get_phy_device(eth_phy_priv_t * priv,uint8_t phy_addr,uint32_t phy_id)49 static eth_phy_dev_t *eth_get_phy_device(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t phy_id)
50 {
51     eth_phy_dev_t *p = eth_phy_devices[0];
52     int32_t i = 0;
53 
54     while (p != NULL)
55     {
56         if ((p->phy_id & p->mask) == (phy_id & p->mask))
57         {
58             p->phy_addr = phy_addr;
59             p->advertising = p->supported = p->features;
60             return p;
61         }
62 
63         i ++;
64         p = eth_phy_devices[i];
65     }
66 
67     return NULL;
68 }
69 
eth_read_phy_id(eth_phy_priv_t * priv,uint8_t phy_addr,uint32_t * phy_id)70 static int32_t eth_read_phy_id(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t *phy_id)
71 {
72     int32_t ret;
73     uint16_t data;
74     uint32_t id;
75 
76     ret = eth_phy_read(priv, phy_addr, CVI_MII_PHYSID1, &data);
77 
78     if (ret != 0)
79     {
80         return ret;
81     }
82 
83     id = data;
84     id = (id & 0xffff) << 16;
85 
86     ret = eth_phy_read(priv, phy_addr, CVI_MII_PHYSID2, &data);
87 
88     if (ret != 0)
89     {
90         return ret;
91     }
92 
93     id |= (data & 0xffff);
94 
95     if (phy_id != NULL)
96     {
97         *phy_id = id;
98     }
99 
100     return 0;
101 }
102 
103 /*
104  * ffs: find first bit set. This is defined the same way as
105  * the libc and compiler builtin ffs routines, therefore
106  * differs in spirit from the above ffz (man ffs).
107  */
ffs(int32_t x)108 static inline int32_t ffs(int32_t x)
109 {
110     int32_t r = 1;
111 
112     if (!x)
113         return 0;
114 
115     if (!(x & 0xffff))
116     {
117         x >>= 16;
118         r += 16;
119     }
120 
121     if (!(x & 0xff))
122     {
123         x >>= 8;
124         r += 8;
125     }
126 
127     if (!(x & 0xf))
128     {
129         x >>= 4;
130         r += 4;
131     }
132 
133     if (!(x & 3))
134     {
135         x >>= 2;
136         r += 2;
137     }
138 
139     if (!(x & 1))
140     {
141         x >>= 1;
142         r += 1;
143     }
144 
145     return r;
146 }
147 
eth_get_phy_by_mask(eth_phy_priv_t * priv,uint32_t phy_mask,phy_if_mode_t interface)148 static eth_phy_dev_t * eth_get_phy_by_mask(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface)
149 {
150     uint32_t phy_id = 0xffffffff;
151 
152     while (phy_mask)
153     {
154         int32_t addr = ffs(phy_mask) - 1;
155         int32_t r = eth_read_phy_id(priv, addr, &phy_id);
156 
157         /* If the PHY ID is mostly f's, we didn't find anything */
158         if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff)
159             return eth_get_phy_device(priv, addr, phy_id);
160 
161         phy_mask &= ~(1 << addr);
162     }
163     return NULL;
164 }
165 
eth_config(void)166 static void eth_config(void)
167 {
168     unsigned int val;
169 
170     val = mmio_read_32(ETH_PHY_BASE) & ETH_PHY_INIT_MASK;
171     mmio_write_32(ETH_PHY_BASE, (val | ETH_PHY_SHUTDOWN) & ETH_PHY_RESET);
172     rt_thread_mdelay(1);
173     mmio_write_32(ETH_PHY_BASE, val & ETH_PHY_POWERUP & ETH_PHY_RESET);
174     rt_thread_mdelay(20);
175     mmio_write_32(ETH_PHY_BASE, (val & ETH_PHY_POWERUP) | ETH_PHY_RESET_N);
176     rt_thread_mdelay(1);
177 }
178 
eth_connect_phy(eth_phy_priv_t * priv,uint32_t phy_mask,phy_if_mode_t interface)179 static eth_phy_dev_t *eth_connect_phy(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface)
180 {
181     int32_t i;
182     eth_phy_dev_t *phydev = NULL;
183 
184     /* config eth internal phy on ASIC board */
185     eth_config();
186 
187 #ifdef CONFIG_PHY_ADDR
188     phy_mask = 1 << CONFIG_PHY_ADDR;
189 #endif
190 
191     for (i = 0; i < 5; i++)
192     {
193         phydev = eth_get_phy_by_mask(priv, phy_mask, interface);
194         if (phydev)
195             return phydev;
196     }
197 
198     rt_kprintf("\n PHY: ");
199     while (phy_mask)
200     {
201         int32_t addr = ffs(phy_mask) - 1;
202         rt_kprintf("%d ", addr);
203         phy_mask &= ~(1 << addr);
204     }
205     rt_kprintf("not found\n");
206 
207     return NULL;
208 }
209 
eth_phy_reset(eth_phy_handle_t handle)210 int32_t eth_phy_reset(eth_phy_handle_t handle)
211 {
212     RT_ASSERT(handle);
213     eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
214     RT_ASSERT(dev->priv);
215 
216     uint16_t data;
217     int32_t ret;
218     int32_t timeout = 600;                                  /* in ms */
219     eth_phy_priv_t *priv = dev->priv;
220     uint32_t phy_addr = dev->phy_addr;
221 
222     /* Soft reset */
223     ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
224     if (ret != 0)
225     {
226         rt_kprintf("eth phy read failed\n");
227         return ret;
228     }
229 
230     ret = eth_phy_write(priv, phy_addr, CVI_MII_BMCR, data | CVI_BMCR_RESET);
231     if (ret != 0)
232     {
233         rt_kprintf("eth phy write failed\n");
234         return ret;
235     }
236 
237 #ifdef CONFIG_PHY_RESET_DELAY
238     rt_hw_us_delay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
239 #endif
240     /*
241      * Wait up to 0.6s for the reset sequence to finish. According to
242      * IEEE 802.3, Section 2, Subsection 22.2.4.1.1 a PHY reset may take
243      * up to 0.5 s.
244      */
245     ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
246     while ((data & CVI_BMCR_RESET) && timeout--)
247     {
248         ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
249 
250         if (ret != 0) {
251             return ret;
252         }
253 
254         rt_thread_mdelay(1);
255     }
256 
257     if (data & CVI_BMCR_RESET)
258     {
259         rt_kprintf("eth phy reset timed out\n");
260         return -1;
261     }
262 
263     return 0;
264 }
265 
eth_phy_config(eth_phy_handle_t handle)266 int32_t eth_phy_config(eth_phy_handle_t handle)
267 {
268     RT_ASSERT(handle);
269     eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
270 
271     if (dev->config)
272     {
273         return dev->config(handle);
274     }
275 
276     return 0;
277 }
278 
eth_phy_start(eth_phy_handle_t handle)279 int32_t eth_phy_start(eth_phy_handle_t handle)
280 {
281     RT_ASSERT(handle);
282     eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
283 
284     if (dev->start)
285     {
286         return dev->start(handle);
287     }
288 
289     return 0;
290 }
291 
eth_phy_stop(eth_phy_handle_t handle)292 int32_t eth_phy_stop(eth_phy_handle_t handle)
293 {
294     RT_ASSERT(handle);
295     eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
296 
297     if (dev->start) {
298         return dev->stop(handle);
299     }
300 
301     return 0;
302 }
303 
cvi_eth_phy_power_control(eth_phy_handle_t handle,eth_power_state_t state)304 int32_t cvi_eth_phy_power_control(eth_phy_handle_t handle, eth_power_state_t state)
305 {
306     if (state == CSI_ETH_POWER_FULL)
307     {
308         return eth_phy_start(handle);
309     }
310     else if (state == CSI_ETH_POWER_OFF)
311     {
312         return eth_phy_stop(handle);
313     }
314 
315     return 0;
316 }
317 
genphy_update_link(eth_phy_dev_t * phy_dev)318 int32_t genphy_update_link(eth_phy_dev_t *phy_dev)
319 {
320     uint8_t phy_addr = phy_dev->phy_addr;
321     uint16_t mii_reg;
322     int32_t ret;
323 
324     /*
325      * Wait if the link is up, and autonegotiation is in progress
326      * (ie - we're capable and it's not done)
327      */
328     ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
329 
330     if (ret != 0) {
331         return ret;
332     }
333 
334     /*
335      * If we already saw the link up, and it hasn't gone down, then
336      * we don't need to wait for autoneg again
337      */
338     if (phy_dev->link_state && mii_reg & CVI_BMSR_LSTATUS)
339         return 0;
340 
341     if ((phy_dev->priv->link_info.autoneg == CSI_ETH_AUTONEG_ENABLE) &&
342         !(mii_reg & CVI_BMSR_ANEGCOMPLETE)) {
343 
344         phy_dev->link_state = ETH_LINK_DOWN;
345         return -1;
346     } else {
347 
348         /* Read the link a second time to clear the latched state */
349         ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
350 
351         if (ret != 0) {
352             return ret;
353         }
354 
355         if (mii_reg & CVI_BMSR_LSTATUS)
356             phy_dev->link_state = ETH_LINK_UP;
357         else
358             phy_dev->link_state = ETH_LINK_DOWN;
359     }
360 
361     return 0;
362 }
363 
eth_phy_update_link(eth_phy_handle_t handle)364 int32_t eth_phy_update_link(eth_phy_handle_t handle)
365 {
366     RT_ASSERT(handle);
367     eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
368 
369     if (dev->update_link) {
370         return dev->update_link(handle);
371     } else {
372         return genphy_update_link(dev);
373     }
374 }
375 
genphy_config_advert(eth_phy_dev_t * phy_dev)376 static int32_t genphy_config_advert(eth_phy_dev_t *phy_dev)
377 {
378     RT_ASSERT(phy_dev->priv);
379 
380     eth_phy_priv_t *priv = phy_dev->priv;
381     uint8_t phy_addr = phy_dev->phy_addr;
382     uint32_t advertise;
383     uint16_t oldadv, adv, bmsr;
384     int32_t changed = 0;
385     int32_t ret;
386 
387     /* Only allow advertising what this PHY supports */
388     phy_dev->advertising &= phy_dev->supported;
389     advertise = phy_dev->advertising;
390 
391     /* Setup standard advertisement */
392     ret = eth_phy_read(priv, phy_addr, CVI_MII_ADVERTISE, &adv);
393     if (ret != 0) {
394         return ret;
395     }
396     oldadv = adv;
397 
398     if (adv < 0)
399         return adv;
400 
401     adv &= ~(CVI_ADVERTISE_ALL | CVI_ADVERTISE_100BASE4 | CVI_ADVERTISE_PAUSE_CAP |
402          CVI_ADVERTISE_PAUSE_ASYM);
403     if (advertise & CVI_ADVERTISED_10baseT_Half)
404         adv |= CVI_ADVERTISE_10HALF;
405     if (advertise & CVI_ADVERTISED_10baseT_Full)
406         adv |= CVI_ADVERTISE_10FULL;
407     if (advertise & CVI_ADVERTISED_100baseT_Half)
408         adv |= CVI_ADVERTISE_100HALF;
409     if (advertise & CVI_ADVERTISED_100baseT_Full)
410         adv |= CVI_ADVERTISE_100FULL;
411     if (advertise & CVI_ADVERTISED_Pause)
412         adv |= CVI_ADVERTISE_PAUSE_CAP;
413     if (advertise & CVI_ADVERTISED_Asym_Pause)
414         adv |= CVI_ADVERTISE_PAUSE_ASYM;
415     if (advertise & CVI_ADVERTISED_1000baseX_Half)
416         adv |= CVI_ADVERTISE_1000XHALF;
417     if (advertise & CVI_ADVERTISED_1000baseX_Full)
418         adv |= CVI_ADVERTISE_1000XFULL;
419 
420     if (adv != oldadv) {
421         ret = eth_phy_write(priv, phy_addr, CVI_MII_ADVERTISE, adv);
422 
423         if (ret != 0) {
424             return ret;
425         }
426         changed = 1;
427     }
428 
429     ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &bmsr);
430 
431     if (ret != 0 || bmsr < 0) {
432         return ret;
433     }
434 
435     /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
436      * 1000Mbits/sec capable PHYs shall have the CVI_BMSR_ESTATEN bit set to a
437      * logical 1.
438      */
439     if (!(bmsr & CVI_BMSR_ESTATEN))
440         return changed;
441 
442     /* Configure gigabit if it's supported */
443     ret = eth_phy_read(priv, phy_addr, CVI_MII_CTRL1000, &adv);
444 
445     if (ret != 0 || adv < 0) {
446         return ret;
447     }
448 
449     oldadv = adv;
450 
451     adv &= ~(CVI_ADVERTISE_1000FULL | CVI_ADVERTISE_1000HALF);
452 
453     if (phy_dev->supported & (CVI_SUPPORTED_1000baseT_Half |
454                 CVI_SUPPORTED_1000baseT_Full)) {
455         if (advertise & CVI_SUPPORTED_1000baseT_Half)
456             adv |= CVI_ADVERTISE_1000HALF;
457         if (advertise & CVI_SUPPORTED_1000baseT_Full)
458             adv |= CVI_ADVERTISE_1000FULL;
459     }
460 
461     if (adv != oldadv)
462         changed = 1;
463 
464     ret = eth_phy_write(priv, phy_addr, CVI_MII_CTRL1000, adv);
465 
466     if (ret != 0) {
467         return ret;
468     }
469 
470     return changed;
471 }
472 
genphy_setup_forced(eth_phy_dev_t * phy_dev)473 static int32_t genphy_setup_forced(eth_phy_dev_t *phy_dev)
474 {
475     RT_ASSERT(phy_dev->priv);
476 
477     eth_phy_priv_t *priv = phy_dev->priv;
478     uint8_t phy_addr = phy_dev->phy_addr;
479     int32_t ctl = CVI_BMCR_ANRESTART;
480     int32_t ret;
481 
482     if (CSI_ETH_SPEED_1G == priv->link_info.speed)
483         ctl |= CVI_BMCR_SPEED1000;
484     else if (CSI_ETH_SPEED_100M == priv->link_info.speed)
485         ctl |= CVI_BMCR_SPEED100;
486     else//CSI_ETH_SPEED_10M == priv->link_info.speed
487         ctl |= CVI_BMCR_SPEED100;
488 
489     if (CSI_ETH_DUPLEX_FULL == priv->link_info.duplex)
490         ctl |= CVI_BMCR_FULLDPLX;
491 
492     ret = eth_phy_write(priv, phy_addr, CVI_MII_BMCR, ctl);
493 
494     return ret;
495 }
496 
genphy_restart_aneg(eth_phy_dev_t * phy_dev)497 int genphy_restart_aneg(eth_phy_dev_t *phy_dev)
498 {
499     int32_t ret;
500     uint16_t ctl;
501     ret = eth_phy_read(phy_dev->priv, phy_dev->phy_addr, CVI_MII_BMCR, &ctl);
502 
503     if (ret != 0 || ctl < 0)
504         return ret;
505 
506     ctl |= (CVI_BMCR_ANENABLE | CVI_BMCR_ANRESTART);
507 
508     /* Don't isolate the PHY if we're negotiating */
509     ctl &= ~(CVI_BMCR_ISOLATE);
510 
511     ret = eth_phy_write(phy_dev->priv, phy_dev->phy_addr, CVI_MII_BMCR, ctl);
512 
513     return ret;
514 }
515 
genphy_config_aneg(eth_phy_dev_t * phy_dev)516 int32_t genphy_config_aneg(eth_phy_dev_t *phy_dev)
517 {
518     RT_ASSERT(phy_dev->priv);
519 
520     eth_phy_priv_t *priv = phy_dev->priv;
521     uint8_t phy_addr = phy_dev->phy_addr;
522     int32_t result;
523     uint16_t ctl;
524     int32_t ret;
525 
526     if (CSI_ETH_AUTONEG_ENABLE != priv->link_info.autoneg)
527         return genphy_setup_forced(phy_dev);
528 
529     result = genphy_config_advert(phy_dev);
530 
531     if (result < 0) /* error */
532         return result;
533 
534     if (result == 0) {
535         /* Advertisment hasn't changed, but maybe aneg was never on to
536          * begin with?  Or maybe phy was isolated? */
537         ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &ctl);
538         if (ret != 0 || ctl < 0)
539             return ret;
540 
541         if (!(ctl & CVI_BMCR_ANENABLE) || (ctl & CVI_BMCR_ISOLATE))
542             result = 1; /* do restart aneg */
543     }
544 
545     /* Only restart aneg if we are advertising something different
546      * than we were before.  */
547     if (result > 0)
548         result = genphy_restart_aneg(phy_dev);
549 
550     return result;
551 }
552 
genphy_config(eth_phy_dev_t * phy_dev)553 int32_t genphy_config(eth_phy_dev_t *phy_dev)
554 {
555     RT_ASSERT(phy_dev->priv);
556 
557     eth_phy_priv_t *priv = phy_dev->priv;
558     uint8_t phy_addr = phy_dev->phy_addr;
559     int32_t ret;
560     uint16_t val;
561     uint32_t features;
562 
563     features = (CVI_SUPPORTED_TP | CVI_SUPPORTED_MII
564             | CVI_SUPPORTED_AUI | CVI_SUPPORTED_FIBRE |
565             CVI_SUPPORTED_BNC);
566 
567     /* Do we support autonegotiation? */
568     ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &val);
569     if (ret != 0 || val < 0)
570         return ret;
571 
572     if (val & CVI_BMSR_ANEGCAPABLE)
573         features |= CVI_SUPPORTED_Autoneg;
574 
575     if (val & CVI_BMSR_100FULL)
576         features |= CVI_SUPPORTED_100baseT_Full;
577     if (val & CVI_BMSR_100HALF)
578         features |= CVI_SUPPORTED_100baseT_Half;
579     if (val & CVI_BMSR_10FULL)
580         features |= CVI_SUPPORTED_10baseT_Full;
581     if (val & CVI_BMSR_10HALF)
582         features |= CVI_SUPPORTED_10baseT_Half;
583 
584     if (val & CVI_BMSR_ESTATEN) {
585         ret = eth_phy_read(priv, phy_addr, CVI_MII_ESTATUS, &val);
586         if (ret != 0 || val < 0)
587             return val;
588 
589         if (val & CVI_ESTATUS_1000_TFULL)
590             features |= CVI_SUPPORTED_1000baseT_Full;
591         if (val & CVI_ESTATUS_1000_THALF)
592             features |= CVI_SUPPORTED_1000baseT_Half;
593         if (val & CVI_ESTATUS_1000_XFULL)
594             features |= CVI_SUPPORTED_1000baseX_Full;
595         if (val & CVI_ESTATUS_1000_XHALF)
596             features |= CVI_SUPPORTED_1000baseX_Half;
597     }
598 
599     phy_dev->supported &= features;
600     phy_dev->advertising &= features;
601 
602     genphy_config_aneg(phy_dev);
603 
604     return 0;
605 }
606 
cvi_eth_phy_init(csi_eth_phy_read_t fn_read,csi_eth_phy_write_t fn_write)607 eth_phy_handle_t cvi_eth_phy_init(csi_eth_phy_read_t  fn_read, csi_eth_phy_write_t fn_write)
608 {
609     eth_phy_dev_t *phy_dev;
610     eth_phy_priv_t *priv;
611     uint32_t phy_mask = 0xffffffff;
612     phy_if_mode_t interface = 0;
613 
614     RT_ASSERT(fn_read != RT_NULL);
615     RT_ASSERT(fn_write != RT_NULL);
616 
617     priv = &phy_priv_list[0];
618 
619     priv->phy_read = fn_read;
620     priv->phy_write = fn_write;
621     priv->link_info.autoneg = CSI_ETH_AUTONEG_ENABLE;
622 
623     phy_dev = eth_connect_phy(priv, phy_mask, interface);
624     if (phy_dev == NULL) {
625         rt_kprintf("No phy device found!\n");
626         return NULL;
627     }
628     rt_kprintf("connect phy id: 0x%X\n", phy_dev->phy_id);
629 
630     phy_dev->priv = priv;
631 
632     /* Reset PHY */
633     eth_phy_reset(phy_dev);
634 
635     /* Config PHY */
636     eth_phy_config(phy_dev);
637 
638     return phy_dev;
639 }
640