mirror of https://github.com/ARMmbed/mbed-os.git
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.pull/7206/head
parent
ed9a1f1327
commit
db672b36c5
|
@ -66,6 +66,8 @@ uint32_t *rx_ptr[ENET_RX_RING_LEN];
|
|||
#define ENET_ALIGN(x,align) ((unsigned int)((x) + ((align)-1)) & (unsigned int)(~(unsigned int)((align)- 1)))
|
||||
|
||||
extern "C" void kinetis_init_eth_hardware(void);
|
||||
extern "C" uint32_t ENET_GetInstance(ENET_Type *base);
|
||||
extern "C" clock_ip_name_t s_enetClock[];
|
||||
|
||||
/* \brief Flags for worker thread */
|
||||
#define FLAG_TX 1
|
||||
|
@ -186,7 +188,6 @@ bool Kinetis_EMAC::low_level_init_successful()
|
|||
phy_speed_t phy_speed;
|
||||
phy_duplex_t phy_duplex;
|
||||
uint32_t phyAddr = 0;
|
||||
bool link = false;
|
||||
enet_config_t config;
|
||||
|
||||
// Allocate RX descriptors
|
||||
|
@ -231,16 +232,16 @@ bool Kinetis_EMAC::low_level_init_successful()
|
|||
|
||||
ENET_GetDefaultConfig(&config);
|
||||
|
||||
PHY_Init(ENET, 0, sysClock);
|
||||
PHY_GetLinkStatus(ENET, phyAddr, &link);
|
||||
if (link) {
|
||||
/* Get link information from PHY */
|
||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
|
||||
/* Change the MII speed and duplex for actual link status. */
|
||||
config.miiSpeed = (enet_mii_speed_t)phy_speed;
|
||||
config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
|
||||
config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
|
||||
if (init_enet_phy(ENET, phyAddr, sysClock) != kStatus_Success) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get link information from PHY */
|
||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
|
||||
/* Change the MII speed and duplex for actual link status. */
|
||||
config.miiSpeed = (enet_mii_speed_t)phy_speed;
|
||||
config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
|
||||
config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
|
||||
config.rxMaxFrameLen = ENET_ETH_MAX_FLEN;
|
||||
config.macSpecialConfig = kENET_ControlFlowControlEnable;
|
||||
config.txAccelerConfig = 0;
|
||||
|
@ -262,6 +263,77 @@ bool Kinetis_EMAC::low_level_init_successful()
|
|||
return true;
|
||||
}
|
||||
|
||||
status_t Kinetis_EMAC::init_enet_phy(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
|
||||
{
|
||||
status_t result = kStatus_Success;
|
||||
uint32_t instance = ENET_GetInstance(base);
|
||||
|
||||
#if TARGET_K66F
|
||||
uint32_t counter = 0xFFFFFU;
|
||||
uint32_t idReg = 0;
|
||||
|
||||
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
||||
/* Set SMI first. */
|
||||
CLOCK_EnableClock(s_enetClock[instance]);
|
||||
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
||||
ENET_SetSMI(base, srcClock_Hz, false);
|
||||
|
||||
/* Initialization after PHY stars to work. */
|
||||
while ((idReg != PHY_CONTROL_ID1) && (counter != 0)) {
|
||||
PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg);
|
||||
counter --;
|
||||
}
|
||||
|
||||
if (!counter) {
|
||||
return kStatus_Fail;
|
||||
}
|
||||
|
||||
counter = 0xFFFFFU;
|
||||
#elif TARGET_K64F
|
||||
/* Set SMI first. */
|
||||
CLOCK_EnableClock(s_enetClock[instance]);
|
||||
ENET_SetSMI(base, srcClock_Hz, false);
|
||||
#else
|
||||
#error invalid target!
|
||||
#endif
|
||||
|
||||
/* Reset PHY. */
|
||||
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
|
||||
return result;
|
||||
}
|
||||
|
||||
status_t Kinetis_EMAC::auto_negotiation(ENET_Type *base, uint32_t phyAddr)
|
||||
{
|
||||
uint32_t bssReg;
|
||||
status_t result;
|
||||
uint32_t counter = 0xFFFFFFU;
|
||||
|
||||
/* Set the negotiation. */
|
||||
result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
|
||||
(PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
|
||||
PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U));
|
||||
if (result == kStatus_Success) {
|
||||
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG,
|
||||
(PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK));
|
||||
if (result == kStatus_Success) {
|
||||
/* Check auto negotiation complete. */
|
||||
while (counter --) {
|
||||
result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg);
|
||||
if (result == kStatus_Success) {
|
||||
if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!counter) {
|
||||
return kStatus_PHY_AutoNegotiateFail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** \brief Allocates a emac_mem_buf_t and returns the data from the incoming packet.
|
||||
*
|
||||
|
@ -452,41 +524,42 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
|
|||
*******************************************************************************/
|
||||
|
||||
#define STATE_UNKNOWN (-1)
|
||||
|
||||
int phy_link_status(void) {
|
||||
bool connection_status;
|
||||
uint32_t phyAddr = 0;
|
||||
|
||||
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
|
||||
return (int)connection_status;
|
||||
}
|
||||
#define STATE_LINK_DOWN (0)
|
||||
#define STATE_LINK_UP (1)
|
||||
|
||||
void Kinetis_EMAC::phy_task()
|
||||
{
|
||||
static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
|
||||
|
||||
uint32_t phyAddr = 0;
|
||||
|
||||
// Get current status
|
||||
PHY_STATE crt_state;
|
||||
bool connection_status;
|
||||
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
|
||||
crt_state.connected = connection_status;
|
||||
// Get the actual PHY link speed
|
||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
|
||||
|
||||
if (connection_status) {
|
||||
crt_state.connected = STATE_LINK_UP;
|
||||
} else {
|
||||
crt_state.connected = STATE_LINK_DOWN;
|
||||
}
|
||||
|
||||
if (crt_state.connected == STATE_LINK_UP) {
|
||||
if (prev_state.connected != STATE_LINK_UP) {
|
||||
auto_negotiation(ENET, phyAddr);
|
||||
}
|
||||
|
||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
|
||||
|
||||
if (prev_state.connected != STATE_LINK_UP || crt_state.speed != prev_state.speed) {
|
||||
/* Poke the registers*/
|
||||
ENET_SetMII(ENET, (enet_mii_speed_t)crt_state.speed, (enet_mii_duplex_t)crt_state.duplex);
|
||||
}
|
||||
}
|
||||
|
||||
// Compare with previous state
|
||||
if (crt_state.connected != prev_state.connected && emac_link_state_cb) {
|
||||
emac_link_state_cb(crt_state.connected);
|
||||
}
|
||||
|
||||
if (crt_state.speed != prev_state.speed) {
|
||||
uint32_t rcr = ENET->RCR;
|
||||
rcr &= ~ENET_RCR_RMII_10T_MASK;
|
||||
rcr |= ENET_RCR_RMII_10T(!crt_state.speed);
|
||||
ENET->RCR = rcr;
|
||||
}
|
||||
|
||||
prev_state = crt_state;
|
||||
}
|
||||
|
||||
|
@ -504,19 +577,20 @@ bool Kinetis_EMAC::power_up()
|
|||
rx_isr();
|
||||
|
||||
/* PHY monitoring task */
|
||||
prev_state.connected = STATE_UNKNOWN;
|
||||
prev_state.connected = STATE_LINK_DOWN;
|
||||
prev_state.speed = (phy_speed_t)STATE_UNKNOWN;
|
||||
prev_state.duplex = (phy_duplex_t)STATE_UNKNOWN;
|
||||
|
||||
phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &Kinetis_EMAC::phy_task));
|
||||
mbed::mbed_event_queue()->call(mbed::callback(this, &Kinetis_EMAC::phy_task));
|
||||
|
||||
/* Allow the PHY task to detect the initial link state and set up the proper flags */
|
||||
osDelay(10);
|
||||
|
||||
phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &Kinetis_EMAC::phy_task));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t Kinetis_EMAC::get_mtu_size() const
|
||||
{
|
||||
return KINETIS_ETH_MTU_SIZE;
|
||||
|
|
|
@ -138,6 +138,8 @@ public:
|
|||
|
||||
private:
|
||||
bool low_level_init_successful();
|
||||
status_t init_enet_phy(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz);
|
||||
status_t auto_negotiation(ENET_Type *base, uint32_t phyAddr);
|
||||
void rx_isr();
|
||||
void tx_isr();
|
||||
void packet_rx();
|
||||
|
|
Loading…
Reference in New Issue