@@ -31,9 +31,11 @@ struct phy_mii_dev_data {
31
31
phy_callback_t cb ;
32
32
void * cb_data ;
33
33
struct k_work_delayable monitor_work ;
34
+ struct k_work_delayable autoneg_work ;
34
35
struct phy_link_state state ;
35
36
struct k_sem sem ;
36
37
bool gigabit_supported ;
38
+ uint32_t autoneg_timeout ;
37
39
};
38
40
39
41
/* Offset to align capabilities bits of 1000BASE-T Control and Status regs */
@@ -145,13 +147,8 @@ static int update_link_state(const struct device *dev)
145
147
struct phy_mii_dev_data * const data = dev -> data ;
146
148
bool link_up ;
147
149
148
- uint16_t anar_reg = 0 ;
149
150
uint16_t bmcr_reg = 0 ;
150
151
uint16_t bmsr_reg = 0 ;
151
- uint16_t anlpar_reg = 0 ;
152
- uint16_t c1kt_reg = 0 ;
153
- uint16_t s1kt_reg = 0 ;
154
- uint32_t timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / 100 ;
155
152
156
153
if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
157
154
return - EIO ;
@@ -178,11 +175,6 @@ static int update_link_state(const struct device *dev)
178
175
LOG_DBG ("PHY (%d) Starting MII PHY auto-negotiate sequence" ,
179
176
cfg -> phy_addr );
180
177
181
- /* Read PHY default advertising parameters */
182
- if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
183
- return - EIO ;
184
- }
185
-
186
178
/* Configure and start auto-negotiation process */
187
179
if (phy_mii_reg_read (dev , MII_BMCR , & bmcr_reg ) < 0 ) {
188
180
return - EIO ;
@@ -195,32 +187,52 @@ static int update_link_state(const struct device *dev)
195
187
return - EIO ;
196
188
}
197
189
198
- /* Wait for the auto-negotiation process to complete */
199
- do {
200
- if (timeout -- == 0U ) {
201
- LOG_DBG ("PHY (%d) auto-negotiate timedout" ,
202
- cfg -> phy_addr );
203
- return - ETIMEDOUT ;
204
- }
190
+ /* We have to wait for the auto-negotiation process to complete */
191
+ data -> autoneg_timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / 100 ;
192
+ return - EINPROGRESS ;
193
+ }
205
194
206
- k_sleep (K_MSEC (100 ));
195
+ static int check_autonegotiation_completion (const struct device * dev )
196
+ {
197
+ const struct phy_mii_dev_config * const cfg = dev -> config ;
198
+ struct phy_mii_dev_data * const data = dev -> data ;
207
199
208
- /* On some PHY chips, the BMSR bits are latched, so the first read may
209
- * show incorrect status. A second read ensures correct values.
210
- */
211
- if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
212
- return - EIO ;
213
- }
200
+ uint16_t anar_reg = 0 ;
201
+ uint16_t bmsr_reg = 0 ;
202
+ uint16_t anlpar_reg = 0 ;
203
+ uint16_t c1kt_reg = 0 ;
204
+ uint16_t s1kt_reg = 0 ;
214
205
215
- /* Second read, clears the latched bits and gives the correct status */
216
- if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
217
- return - EIO ;
206
+ /* On some PHY chips, the BMSR bits are latched, so the first read may
207
+ * show incorrect status. A second read ensures correct values.
208
+ */
209
+ if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
210
+ return - EIO ;
211
+ }
212
+
213
+ /* Second read, clears the latched bits and gives the correct status */
214
+ if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
215
+ return - EIO ;
216
+ }
217
+
218
+ if (!(bmsr_reg & MII_BMSR_AUTONEG_COMPLETE )) {
219
+ if (data -> autoneg_timeout -- == 0U ) {
220
+ LOG_DBG ("PHY (%d) auto-negotiate timedout" ,
221
+ cfg -> phy_addr );
222
+ return - ETIMEDOUT ;
218
223
}
219
- } while (!(bmsr_reg & MII_BMSR_AUTONEG_COMPLETE ));
224
+ return - EINPROGRESS ;
225
+ }
220
226
221
227
LOG_DBG ("PHY (%d) auto-negotiate sequence completed" ,
222
228
cfg -> phy_addr );
223
229
230
+ /* Read PHY default advertising parameters */
231
+ if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
232
+ return - EIO ;
233
+ }
234
+ LOG_ERR ("ANAR after %04x" , anar_reg );
235
+
224
236
/** Read peer device capability */
225
237
if (phy_mii_reg_read (dev , MII_ANLPAR , & anlpar_reg ) < 0 ) {
226
238
return - EIO ;
@@ -294,9 +306,45 @@ static void monitor_work_handler(struct k_work *work)
294
306
invoke_link_cb (dev );
295
307
}
296
308
297
- /* Submit delayed work */
298
- k_work_reschedule (& data -> monitor_work ,
299
- K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
309
+ if (rc == - EINPROGRESS ) {
310
+ /* Check for autonegotiation completion */
311
+ k_work_reschedule (& data -> autoneg_work ,
312
+ K_MSEC (100 ));
313
+ } else {
314
+ /* Submit delayed work */
315
+ k_work_reschedule (& data -> monitor_work ,
316
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
317
+ }
318
+ }
319
+
320
+ static void autoneg_work_handler (struct k_work * work )
321
+ {
322
+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
323
+ struct phy_mii_dev_data * const data =
324
+ CONTAINER_OF (dwork , struct phy_mii_dev_data , autoneg_work );
325
+ const struct device * dev = data -> dev ;
326
+ int rc ;
327
+
328
+ k_sem_take (& data -> sem , K_FOREVER );
329
+
330
+ rc = check_autonegotiation_completion (dev );
331
+
332
+ k_sem_give (& data -> sem );
333
+
334
+ /* If link state has changed and a callback is set, invoke callback */
335
+ if (rc == 0 ) {
336
+ invoke_link_cb (dev );
337
+ }
338
+
339
+ if (rc == - EINPROGRESS ) {
340
+ /* Check again soon */
341
+ k_work_reschedule (& data -> autoneg_work ,
342
+ K_MSEC (100 ));
343
+ } else {
344
+ /* Schedule the next monitoring call */
345
+ k_work_reschedule (& data -> monitor_work ,
346
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
347
+ }
300
348
}
301
349
302
350
static int phy_mii_read (const struct device * dev , uint16_t reg_addr ,
@@ -479,6 +527,8 @@ static int phy_mii_initialize(const struct device *dev)
479
527
480
528
k_work_init_delayable (& data -> monitor_work ,
481
529
monitor_work_handler );
530
+ k_work_init_delayable (& data -> autoneg_work ,
531
+ autoneg_work_handler );
482
532
483
533
monitor_work_handler (& data -> monitor_work .work );
484
534
}
0 commit comments