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