@@ -39,6 +39,7 @@ struct phy_mii_dev_data {
39
39
struct k_work_delayable monitor_work ;
40
40
struct k_work_delayable autoneg_work ;
41
41
bool gigabit_supported ;
42
+ bool restart_autoneg ;
42
43
uint32_t autoneg_timeout ;
43
44
#endif
44
45
};
@@ -175,16 +176,19 @@ static int update_link_state(const struct device *dev)
175
176
link_up = bmsr_reg & MII_BMSR_LINK_STATUS ;
176
177
177
178
/* If there is no change in link state don't proceed. */
178
- if (link_up == data -> state .is_up ) {
179
+ if (( link_up == data -> state .is_up ) && ! data -> restart_autoneg ) {
179
180
return - EAGAIN ;
180
181
}
181
182
182
183
data -> state .is_up = link_up ;
183
184
184
- /* If link is down, there is nothing more to be done */
185
- if ( data -> state .is_up == false) {
185
+ if (! data -> state . is_up ) {
186
+ data -> state .speed = 0 ;
186
187
LOG_INF ("PHY (%d) is down" , cfg -> phy_addr );
187
- return 0 ;
188
+ /* If not restarting auto-negotiation, just return */
189
+ if (!data -> restart_autoneg ) {
190
+ return 0 ;
191
+ }
188
192
}
189
193
190
194
/**
@@ -205,6 +209,8 @@ static int update_link_state(const struct device *dev)
205
209
return - EIO ;
206
210
}
207
211
212
+ data -> restart_autoneg = false;
213
+
208
214
/* We have to wait for the auto-negotiation process to complete */
209
215
data -> autoneg_timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / MII_AUTONEG_POLL_INTERVAL_MS ;
210
216
return - EINPROGRESS ;
@@ -221,6 +227,10 @@ static int check_autonegotiation_completion(const struct device *dev)
221
227
uint16_t c1kt_reg = 0 ;
222
228
uint16_t s1kt_reg = 0 ;
223
229
230
+ if (data -> restart_autoneg ) {
231
+ return - EAGAIN ;
232
+ }
233
+
224
234
/* On some PHY chips, the BMSR bits are latched, so the first read may
225
235
* show incorrect status. A second read ensures correct values.
226
236
*/
@@ -280,6 +290,8 @@ static int check_autonegotiation_completion(const struct device *dev)
280
290
data -> state .speed = LINK_HALF_10BASE ;
281
291
}
282
292
293
+ data -> state .is_up = (bmsr_reg & MII_BMSR_LINK_STATUS ) != 0U ;
294
+
283
295
LOG_INF ("PHY (%d) Link speed %s Mb, %s duplex" ,
284
296
cfg -> phy_addr ,
285
297
PHY_LINK_IS_SPEED_1000M (data -> state .speed ) ? "1000" :
@@ -376,8 +388,11 @@ static int phy_mii_cfg_link(const struct device *dev,
376
388
struct phy_mii_dev_data * const data = dev -> data ;
377
389
const struct phy_mii_dev_config * const cfg = dev -> config ;
378
390
uint16_t anar_reg ;
391
+ uint16_t anar_reg_old ;
379
392
uint16_t bmcr_reg ;
380
393
uint16_t c1kt_reg ;
394
+ uint16_t c1kt_reg_old ;
395
+ int ret = 0 ;
381
396
382
397
/* if there is no mdio (fixed-link) it is not supported to configure link */
383
398
if (cfg -> fixed ) {
@@ -388,17 +403,23 @@ static int phy_mii_cfg_link(const struct device *dev,
388
403
return - ENODEV ;
389
404
}
390
405
406
+ k_sem_take (& data -> sem , K_FOREVER );
407
+
391
408
if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
392
- return - EIO ;
409
+ ret = - EIO ;
410
+ goto cfg_link_end ;
393
411
}
412
+ anar_reg_old = anar_reg ;
394
413
395
414
if (phy_mii_reg_read (dev , MII_BMCR , & bmcr_reg ) < 0 ) {
396
- return - EIO ;
415
+ ret = - EIO ;
416
+ goto cfg_link_end ;
397
417
}
398
418
399
419
if (data -> gigabit_supported ) {
400
420
if (phy_mii_reg_read (dev , MII_1KTCR , & c1kt_reg ) < 0 ) {
401
- return - EIO ;
421
+ ret = - EIO ;
422
+ goto cfg_link_end ;
402
423
}
403
424
}
404
425
@@ -427,6 +448,8 @@ static int phy_mii_cfg_link(const struct device *dev,
427
448
}
428
449
429
450
if (data -> gigabit_supported ) {
451
+ c1kt_reg_old = c1kt_reg ;
452
+
430
453
if (adv_speeds & LINK_FULL_1000BASE ) {
431
454
c1kt_reg |= MII_ADVERTISE_1000_FULL ;
432
455
} else {
@@ -439,22 +462,41 @@ static int phy_mii_cfg_link(const struct device *dev,
439
462
c1kt_reg &= ~MII_ADVERTISE_1000_HALF ;
440
463
}
441
464
442
- if (phy_mii_reg_write (dev , MII_1KTCR , c1kt_reg ) < 0 ) {
443
- return - EIO ;
465
+ if (c1kt_reg != c1kt_reg_old ) {
466
+ if (phy_mii_reg_write (dev , MII_1KTCR , c1kt_reg ) < 0 ) {
467
+ ret = - EIO ;
468
+ goto cfg_link_end ;
469
+ }
470
+
471
+ data -> restart_autoneg = true;
444
472
}
445
473
}
446
474
447
- bmcr_reg |= MII_BMCR_AUTONEG_ENABLE ;
475
+ if (anar_reg != anar_reg_old ) {
476
+ if (phy_mii_reg_write (dev , MII_ANAR , anar_reg ) < 0 ) {
477
+ ret = - EIO ;
478
+ goto cfg_link_end ;
479
+ }
448
480
449
- if (phy_mii_reg_write (dev , MII_ANAR , anar_reg ) < 0 ) {
450
- return - EIO ;
481
+ data -> restart_autoneg = true;
451
482
}
452
483
453
- if (phy_mii_reg_write (dev , MII_BMCR , bmcr_reg ) < 0 ) {
454
- return - EIO ;
484
+ if ((bmcr_reg & MII_BMCR_AUTONEG_ENABLE ) == 0U ) {
485
+ if (phy_mii_reg_write (dev , MII_BMCR , bmcr_reg | MII_BMCR_AUTONEG_ENABLE ) < 0 ) {
486
+ ret = - EIO ;
487
+ goto cfg_link_end ;
488
+ }
455
489
}
456
490
457
- return 0 ;
491
+ if (data -> restart_autoneg && data -> state .is_up ) {
492
+ k_work_cancel_delayable (& data -> autoneg_work );
493
+ k_work_reschedule (& data -> monitor_work , K_NO_WAIT );
494
+ }
495
+
496
+ cfg_link_end :
497
+ k_sem_give (& data -> sem );
498
+
499
+ return ret ;
458
500
}
459
501
#endif /* ANY_DYNAMIC_LINK */
460
502
@@ -467,6 +509,13 @@ static int phy_mii_get_link_state(const struct device *dev,
467
509
468
510
memcpy (state , & data -> state , sizeof (struct phy_link_state ));
469
511
512
+ if (data -> state .speed == 0 ) {
513
+ /* If speed is 0, then link is also down, happens when autonegotiation is in
514
+ * progress
515
+ */
516
+ data -> state .is_up = false;
517
+ }
518
+
470
519
k_sem_give (& data -> sem );
471
520
472
521
return 0 ;
@@ -558,6 +607,9 @@ static int phy_mii_initialize_dynamic_link(const struct device *dev)
558
607
559
608
data -> gigabit_supported = is_gigabit_supported (dev );
560
609
610
+ k_work_init_delayable (& data -> monitor_work , monitor_work_handler );
611
+ k_work_init_delayable (& data -> autoneg_work , autoneg_work_handler );
612
+
561
613
/* Advertise all speeds */
562
614
phy_mii_cfg_link (dev , LINK_HALF_10BASE |
563
615
LINK_FULL_10BASE |
@@ -566,9 +618,6 @@ static int phy_mii_initialize_dynamic_link(const struct device *dev)
566
618
LINK_HALF_1000BASE |
567
619
LINK_FULL_1000BASE );
568
620
569
- k_work_init_delayable (& data -> monitor_work , monitor_work_handler );
570
- k_work_init_delayable (& data -> autoneg_work , autoneg_work_handler );
571
-
572
621
monitor_work_handler (& data -> monitor_work .work );
573
622
574
623
return 0 ;
0 commit comments