Skip to content

Commit db672b3

Browse files
author
Mika Leppänen
committed
Non-blocking K64F/K66F ethernet power up
Changed K64F/K66F power up to return without waiting for link up i.e. for the ethernet cable to be connected. This is needed for non-blocking use of driver e.g. for using the driver from event queue.
1 parent ed9a1f1 commit db672b3

File tree

2 files changed

+109
-33
lines changed

2 files changed

+109
-33
lines changed

features/netsocket/emac-drivers/TARGET_Freescale_EMAC/kinetis_emac.cpp

Lines changed: 107 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ uint32_t *rx_ptr[ENET_RX_RING_LEN];
6666
#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1)))
6767

6868
extern "C" void kinetis_init_eth_hardware(void);
69+
extern "C" uint32_t ENET_GetInstance(ENET_Type *base);
70+
extern "C" clock_ip_name_t s_enetClock[];
6971

7072
/* \brief Flags for worker thread */
7173
#define FLAG_TX 1
@@ -186,7 +188,6 @@ bool Kinetis_EMAC::low_level_init_successful()
186188
phy_speed_t phy_speed;
187189
phy_duplex_t phy_duplex;
188190
uint32_t phyAddr = 0;
189-
bool link = false;
190191
enet_config_t config;
191192

192193
// Allocate RX descriptors
@@ -231,16 +232,16 @@ bool Kinetis_EMAC::low_level_init_successful()
231232

232233
ENET_GetDefaultConfig(&config);
233234

234-
PHY_Init(ENET, 0, sysClock);
235-
PHY_GetLinkStatus(ENET, phyAddr, &link);
236-
if (link) {
237-
/* Get link information from PHY */
238-
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
239-
/* Change the MII speed and duplex for actual link status. */
240-
config.miiSpeed = (enet_mii_speed_t)phy_speed;
241-
config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
242-
config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
235+
if (init_enet_phy(ENET, phyAddr, sysClock) != kStatus_Success) {
236+
return false;
243237
}
238+
239+
/* Get link information from PHY */
240+
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
241+
/* Change the MII speed and duplex for actual link status. */
242+
config.miiSpeed = (enet_mii_speed_t)phy_speed;
243+
config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
244+
config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
244245
config.rxMaxFrameLen = ENET_ETH_MAX_FLEN;
245246
config.macSpecialConfig = kENET_ControlFlowControlEnable;
246247
config.txAccelerConfig = 0;
@@ -262,6 +263,77 @@ bool Kinetis_EMAC::low_level_init_successful()
262263
return true;
263264
}
264265

266+
status_t Kinetis_EMAC::init_enet_phy(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
267+
{
268+
status_t result = kStatus_Success;
269+
uint32_t instance = ENET_GetInstance(base);
270+
271+
#if TARGET_K66F
272+
uint32_t counter = 0xFFFFFU;
273+
uint32_t idReg = 0;
274+
275+
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
276+
/* Set SMI first. */
277+
CLOCK_EnableClock(s_enetClock[instance]);
278+
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
279+
ENET_SetSMI(base, srcClock_Hz, false);
280+
281+
/* Initialization after PHY stars to work. */
282+
while ((idReg != PHY_CONTROL_ID1) && (counter != 0)) {
283+
PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
284+
counter --;
285+
}
286+
287+
if (!counter) {
288+
return kStatus_Fail;
289+
}
290+
291+
counter = 0xFFFFFU;
292+
#elif TARGET_K64F
293+
/* Set SMI first. */
294+
CLOCK_EnableClock(s_enetClock[instance]);
295+
ENET_SetSMI(base, srcClock_Hz, false);
296+
#else
297+
#error invalid target!
298+
#endif
299+
300+
/* Reset PHY. */
301+
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
302+
return result;
303+
}
304+
305+
status_t Kinetis_EMAC::auto_negotiation(ENET_Type *base, uint32_t phyAddr)
306+
{
307+
uint32_t bssReg;
308+
status_t result;
309+
uint32_t counter = 0xFFFFFFU;
310+
311+
/* Set the negotiation. */
312+
result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
313+
(PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
314+
PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
315+
if (result == kStatus_Success) {
316+
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG,
317+
(PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
318+
if (result == kStatus_Success) {
319+
/* Check auto negotiation complete. */
320+
while (counter --) {
321+
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
322+
if (result == kStatus_Success) {
323+
if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) {
324+
break;
325+
}
326+
}
327+
328+
if (!counter) {
329+
return kStatus_PHY_AutoNegotiateFail;
330+
}
331+
}
332+
}
333+
}
334+
335+
return result;
336+
}
265337

266338
/** \brief Allocates a emac_mem_buf_t and returns the data from the incoming packet.
267339
*
@@ -452,41 +524,42 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
452524
*******************************************************************************/
453525

454526
#define STATE_UNKNOWN (-1)
455-
456-
int phy_link_status(void) {
457-
bool connection_status;
458-
uint32_t phyAddr = 0;
459-
460-
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
461-
return (int)connection_status;
462-
}
527+
#define STATE_LINK_DOWN (0)
528+
#define STATE_LINK_UP (1)
463529

464530
void Kinetis_EMAC::phy_task()
465531
{
466-
static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
467-
468532
uint32_t phyAddr = 0;
469533

470534
// Get current status
471535
PHY_STATE crt_state;
472536
bool connection_status;
473537
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
474-
crt_state.connected = connection_status;
475-
// Get the actual PHY link speed
476-
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
538+
539+
if (connection_status) {
540+
crt_state.connected = STATE_LINK_UP;
541+
} else {
542+
crt_state.connected = STATE_LINK_DOWN;
543+
}
544+
545+
if (crt_state.connected == STATE_LINK_UP) {
546+
if (prev_state.connected != STATE_LINK_UP) {
547+
auto_negotiation(ENET, phyAddr);
548+
}
549+
550+
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
551+
552+
if (prev_state.connected != STATE_LINK_UP || crt_state.speed != prev_state.speed) {
553+
/* Poke the registers*/
554+
ENET_SetMII(ENET, (enet_mii_speed_t)crt_state.speed, (enet_mii_duplex_t)crt_state.duplex);
555+
}
556+
}
477557

478558
// Compare with previous state
479559
if (crt_state.connected != prev_state.connected && emac_link_state_cb) {
480560
emac_link_state_cb(crt_state.connected);
481561
}
482562

483-
if (crt_state.speed != prev_state.speed) {
484-
uint32_t rcr = ENET->RCR;
485-
rcr &= ~ENET_RCR_RMII_10T_MASK;
486-
rcr |= ENET_RCR_RMII_10T(!crt_state.speed);
487-
ENET->RCR = rcr;
488-
}
489-
490563
prev_state = crt_state;
491564
}
492565

@@ -504,19 +577,20 @@ bool Kinetis_EMAC::power_up()
504577
rx_isr();
505578

506579
/* PHY monitoring task */
507-
prev_state.connected = STATE_UNKNOWN;
580+
prev_state.connected = STATE_LINK_DOWN;
508581
prev_state.speed = (phy_speed_t)STATE_UNKNOWN;
509582
prev_state.duplex = (phy_duplex_t)STATE_UNKNOWN;
510583

511-
phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &Kinetis_EMAC::phy_task));
584+
mbed::mbed_event_queue()->call(mbed::callback(this, &Kinetis_EMAC::phy_task));
512585

513586
/* Allow the PHY task to detect the initial link state and set up the proper flags */
514587
osDelay(10);
515588

589+
phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &Kinetis_EMAC::phy_task));
590+
516591
return true;
517592
}
518593

519-
520594
uint32_t Kinetis_EMAC::get_mtu_size() const
521595
{
522596
return KINETIS_ETH_MTU_SIZE;

features/netsocket/emac-drivers/TARGET_Freescale_EMAC/kinetis_emac.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class Kinetis_EMAC : public EMAC {
138138

139139
private:
140140
bool low_level_init_successful();
141+
status_t init_enet_phy(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz);
142+
status_t auto_negotiation(ENET_Type *base, uint32_t phyAddr);
141143
void rx_isr();
142144
void tx_isr();
143145
void packet_rx();

0 commit comments

Comments
 (0)