Merge pull request #7206 from mikaleppanen/k64f_async_powerup

K64f non-blocking powerup
pull/7271/head
Cruz Monrreal 2018-06-19 21:49:37 -05:00 committed by GitHub
commit e8005f6d72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 153 additions and 107 deletions

View File

@ -186,7 +186,6 @@ bool Kinetis_EMAC::low_level_init_successful()
phy_speed_t phy_speed; phy_speed_t phy_speed;
phy_duplex_t phy_duplex; phy_duplex_t phy_duplex;
uint32_t phyAddr = 0; uint32_t phyAddr = 0;
bool link = false;
enet_config_t config; enet_config_t config;
// Allocate RX descriptors // Allocate RX descriptors
@ -231,16 +230,16 @@ bool Kinetis_EMAC::low_level_init_successful()
ENET_GetDefaultConfig(&config); ENET_GetDefaultConfig(&config);
PHY_Init(ENET, 0, sysClock); if (PHY_Init(ENET, phyAddr, sysClock) != kStatus_Success) {
PHY_GetLinkStatus(ENET, phyAddr, &link); return false;
if (link) { }
/* Get link information from PHY */ /* Get link information from PHY */
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex); PHY_GetLinkSpeedDuplex(ENET, phyAddr, &phy_speed, &phy_duplex);
/* Change the MII speed and duplex for actual link status. */ /* Change the MII speed and duplex for actual link status. */
config.miiSpeed = (enet_mii_speed_t)phy_speed; config.miiSpeed = (enet_mii_speed_t)phy_speed;
config.miiDuplex = (enet_mii_duplex_t)phy_duplex; config.miiDuplex = (enet_mii_duplex_t)phy_duplex;
config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt; config.interrupt = kENET_RxFrameInterrupt | kENET_TxFrameInterrupt;
}
config.rxMaxFrameLen = ENET_ETH_MAX_FLEN; config.rxMaxFrameLen = ENET_ETH_MAX_FLEN;
config.macSpecialConfig = kENET_ControlFlowControlEnable; config.macSpecialConfig = kENET_ControlFlowControlEnable;
config.txAccelerConfig = 0; config.txAccelerConfig = 0;
@ -262,7 +261,6 @@ bool Kinetis_EMAC::low_level_init_successful()
return true; return true;
} }
/** \brief Allocates a emac_mem_buf_t and returns the data from the incoming packet. /** \brief Allocates a emac_mem_buf_t and returns the data from the incoming packet.
* *
* \param[in] idx index of packet to be read * \param[in] idx index of packet to be read
@ -413,8 +411,8 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
buf = copy_buf; buf = copy_buf;
} }
/* Check if a descriptor is available for the transfer. */ /* Check if a descriptor is available for the transfer (wait 10ms before dropping the buffer) */
if (xTXDCountSem.wait(0) == 0) { if (xTXDCountSem.wait(10) == 0) {
memory_manager->free(buf); memory_manager->free(buf);
return false; return false;
} }
@ -452,41 +450,42 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
*******************************************************************************/ *******************************************************************************/
#define STATE_UNKNOWN (-1) #define STATE_UNKNOWN (-1)
#define STATE_LINK_DOWN (0)
int phy_link_status(void) { #define STATE_LINK_UP (1)
bool connection_status;
uint32_t phyAddr = 0;
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
return (int)connection_status;
}
void Kinetis_EMAC::phy_task() 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; uint32_t phyAddr = 0;
// Get current status // Get current status
PHY_STATE crt_state; PHY_STATE crt_state;
bool connection_status; bool connection_status;
PHY_GetLinkStatus(ENET, phyAddr, &connection_status); PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
crt_state.connected = connection_status;
// Get the actual PHY link speed 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) {
PHY_AutoNegotiation(ENET, phyAddr);
}
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex); 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 // Compare with previous state
if (crt_state.connected != prev_state.connected && emac_link_state_cb) { if (crt_state.connected != prev_state.connected && emac_link_state_cb) {
emac_link_state_cb(crt_state.connected); 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; prev_state = crt_state;
} }
@ -504,19 +503,20 @@ bool Kinetis_EMAC::power_up()
rx_isr(); rx_isr();
/* PHY monitoring task */ /* PHY monitoring task */
prev_state.connected = STATE_UNKNOWN; prev_state.connected = STATE_LINK_DOWN;
prev_state.speed = (phy_speed_t)STATE_UNKNOWN; prev_state.speed = (phy_speed_t)STATE_UNKNOWN;
prev_state.duplex = (phy_duplex_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 */ /* Allow the PHY task to detect the initial link state and set up the proper flags */
osDelay(10); osDelay(10);
phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &Kinetis_EMAC::phy_task));
return true; return true;
} }
uint32_t Kinetis_EMAC::get_mtu_size() const uint32_t Kinetis_EMAC::get_mtu_size() const
{ {
return KINETIS_ETH_MTU_SIZE; return KINETIS_ETH_MTU_SIZE;

View File

@ -64,7 +64,6 @@ extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
{ {
uint32_t bssReg;
uint32_t counter = PHY_TIMEOUT_COUNT; uint32_t counter = PHY_TIMEOUT_COUNT;
uint32_t idReg = 0; uint32_t idReg = 0;
status_t result = kStatus_Success; status_t result = kStatus_Success;
@ -89,10 +88,17 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
} }
/* Reset PHY. */ /* Reset PHY. */
counter = PHY_TIMEOUT_COUNT;
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
if (result == kStatus_Success)
return result;
}
status_t PHY_AutoNegotiation(ENET_Type *base, uint32_t phyAddr)
{ {
status_t result = kStatus_Success;
uint32_t bssReg;
uint32_t counter = PHY_TIMEOUT_COUNT;
/* Set the negotiation. */ /* Set the negotiation. */
result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
(PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
@ -122,7 +128,6 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
} }
} }
} }
}
return result; return result;
} }

View File

@ -136,10 +136,19 @@ extern "C" {
* @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI.
* @retval kStatus_Success PHY initialize success * @retval kStatus_Success PHY initialize success
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
* @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail
*/ */
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz); status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz);
/*!
* @brief Initiates auto negotiation.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @retval kStatus_Success PHY auto negotiation success
* @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail
*/
status_t PHY_AutoNegotiation(ENET_Type *base, uint32_t phyAddr);
/*! /*!
* @brief PHY Write function. This function write data over the SMI to * @brief PHY Write function. This function write data over the SMI to
* the specified PHY register. This function is called by all PHY interfaces. * the specified PHY register. This function is called by all PHY interfaces.

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright (c) 2015, Freescale Semiconductor, Inc.
* All rights reserved. * Copyright 2016-2017 NXP
* *
* Redistribution and use in source and binary forms, with or without modification, * Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met: * are permitted provided that the following conditions are met:
@ -12,7 +12,7 @@
* list of conditions and the following disclaimer in the documentation and/or * list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution. * other materials provided with the distribution.
* *
* o Neither the name of Freescale Semiconductor, Inc. nor the names of its * o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this * contributors may be used to endorse or promote products derived from this
* software without specific prior written permission. * software without specific prior written permission.
* *
@ -53,8 +53,10 @@ extern uint32_t ENET_GetInstance(ENET_Type *base);
* Variables * Variables
******************************************************************************/ ******************************************************************************/
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/*! @brief Pointers to enet clocks for each instance. */ /*! @brief Pointers to enet clocks for each instance. */
extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
/******************************************************************************* /*******************************************************************************
* Code * Code
@ -62,19 +64,41 @@ extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT];
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
{ {
uint32_t bssReg;
uint32_t counter = PHY_TIMEOUT_COUNT; uint32_t counter = PHY_TIMEOUT_COUNT;
uint32_t idReg = 0;
status_t result = kStatus_Success; status_t result = kStatus_Success;
uint32_t instance = ENET_GetInstance(base); uint32_t instance = ENET_GetInstance(base);
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
/* Set SMI first. */ /* Set SMI first. */
CLOCK_EnableClock(s_enetClock[instance]); CLOCK_EnableClock(s_enetClock[instance]);
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
ENET_SetSMI(base, srcClock_Hz, false); 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;
}
/* Reset PHY. */ /* Reset PHY. */
result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK);
if (result == kStatus_Success)
return result;
}
status_t PHY_AutoNegotiation(ENET_Type *base, uint32_t phyAddr)
{ {
status_t result = kStatus_Success;
uint32_t bssReg;
uint32_t counter = PHY_TIMEOUT_COUNT;
/* Set the negotiation. */ /* Set the negotiation. */
result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG,
(PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK |
@ -104,7 +128,6 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz)
} }
} }
} }
}
return result; return result;
} }

View File

@ -136,10 +136,19 @@ extern "C" {
* @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI.
* @retval kStatus_Success PHY initialize success * @retval kStatus_Success PHY initialize success
* @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out
* @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail
*/ */
status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz); status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz);
/*!
* @brief Initiates auto negotiation.
*
* @param base ENET peripheral base address.
* @param phyAddr The PHY address.
* @retval kStatus_Success PHY auto negotiation success
* @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail
*/
status_t PHY_AutoNegotiation(ENET_Type *base, uint32_t phyAddr);
/*! /*!
* @brief PHY Write function. This function write data over the SMI to * @brief PHY Write function. This function write data over the SMI to
* the specified PHY register. This function is called by all PHY interfaces. * the specified PHY register. This function is called by all PHY interfaces.