@@ -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,51 @@ 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
+
224
235
/** Read peer device capability */
225
236
if (phy_mii_reg_read (dev , MII_ANLPAR , & anlpar_reg ) < 0 ) {
226
237
return - EIO ;
@@ -294,9 +305,45 @@ static void monitor_work_handler(struct k_work *work)
294
305
invoke_link_cb (dev );
295
306
}
296
307
297
- /* Submit delayed work */
298
- k_work_reschedule (& data -> monitor_work ,
299
- K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
308
+ if (rc == - EINPROGRESS ) {
309
+ /* Check for autonegotiation completion */
310
+ k_work_reschedule (& data -> autoneg_work ,
311
+ K_MSEC (100 ));
312
+ } else {
313
+ /* Submit delayed work */
314
+ k_work_reschedule (& data -> monitor_work ,
315
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
316
+ }
317
+ }
318
+
319
+ static void autoneg_work_handler (struct k_work * work )
320
+ {
321
+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
322
+ struct phy_mii_dev_data * const data =
323
+ CONTAINER_OF (dwork , struct phy_mii_dev_data , autoneg_work );
324
+ const struct device * dev = data -> dev ;
325
+ int rc ;
326
+
327
+ k_sem_take (& data -> sem , K_FOREVER );
328
+
329
+ rc = check_autonegotiation_completion (dev );
330
+
331
+ k_sem_give (& data -> sem );
332
+
333
+ /* If link state has changed and a callback is set, invoke callback */
334
+ if (rc == 0 ) {
335
+ invoke_link_cb (dev );
336
+ }
337
+
338
+ if (rc == - EINPROGRESS ) {
339
+ /* Check again soon */
340
+ k_work_reschedule (& data -> autoneg_work ,
341
+ K_MSEC (100 ));
342
+ } else {
343
+ /* Schedule the next monitoring call */
344
+ k_work_reschedule (& data -> monitor_work ,
345
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
346
+ }
300
347
}
301
348
302
349
static int phy_mii_read (const struct device * dev , uint16_t reg_addr ,
@@ -479,6 +526,8 @@ static int phy_mii_initialize(const struct device *dev)
479
526
480
527
k_work_init_delayable (& data -> monitor_work ,
481
528
monitor_work_handler );
529
+ k_work_init_delayable (& data -> autoneg_work ,
530
+ autoneg_work_handler );
482
531
483
532
monitor_work_handler (& data -> monitor_work .work );
484
533
}
0 commit comments