diff --git a/features/netsocket/emac-drivers/TARGET_Freescale_EMAC/kinetis_emac.cpp b/features/netsocket/emac-drivers/TARGET_Freescale_EMAC/kinetis_emac.cpp index c091e0b8e9..860e6b22a9 100644 --- a/features/netsocket/emac-drivers/TARGET_Freescale_EMAC/kinetis_emac.cpp +++ b/features/netsocket/emac-drivers/TARGET_Freescale_EMAC/kinetis_emac.cpp @@ -186,7 +186,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 +230,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 (PHY_Init(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,7 +261,6 @@ bool Kinetis_EMAC::low_level_init_successful() return true; } - /** \brief Allocates a emac_mem_buf_t and returns the data from the incoming packet. * * \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; } - /* Check if a descriptor is available for the transfer. */ - if (xTXDCountSem.wait(0) == 0) { + /* Check if a descriptor is available for the transfer (wait 10ms before dropping the buffer) */ + if (xTXDCountSem.wait(10) == 0) { memory_manager->free(buf); return false; } @@ -452,41 +450,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) { + PHY_AutoNegotiation(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 +503,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; diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.c index a5bef533d5..7faf4e87c6 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.c @@ -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) { - uint32_t bssReg; uint32_t counter = PHY_TIMEOUT_COUNT; uint32_t idReg = 0; status_t result = kStatus_Success; @@ -89,36 +88,42 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) } /* Reset PHY. */ - counter = PHY_TIMEOUT_COUNT; result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + + 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. */ + 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) { - /* 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)); + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); 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 --) { - /* Check auto negotiation complete. */ - while (counter --) + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); + if ( result == kStatus_Success) { - result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); - if ( result == kStatus_Success) + if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) { - if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) - { - break; - } + break; } + } - if (!counter) - { - return kStatus_PHY_AutoNegotiateFail; - } + if (!counter) + { + return kStatus_PHY_AutoNegotiateFail; } } } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.h index 9353bea798..abc972e4a1 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/TARGET_FRDM/fsl_phy.h @@ -136,10 +136,19 @@ extern "C" { * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. * @retval kStatus_Success PHY initialize success * @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); +/*! + * @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 * the specified PHY register. This function is called by all PHY interfaces. diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.c index 961a97f339..7faf4e87c6 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.c @@ -1,32 +1,32 @@ /* -* Copyright (c) 2015, Freescale Semiconductor, Inc. -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without modification, -* are permitted provided that the following conditions are met: -* -* o Redistributions of source code must retain the above copyright notice, this list -* of conditions and the following disclaimer. -* -* o Redistributions in binary form must reproduce the above copyright notice, this -* list of conditions and the following disclaimer in the documentation and/or -* other materials provided with the distribution. -* -* o Neither the name of Freescale Semiconductor, Inc. nor the names of its -* contributors may be used to endorse or promote products derived from this -* software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 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 + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ #include "fsl_phy.h" @@ -53,8 +53,10 @@ extern uint32_t ENET_GetInstance(ENET_Type *base); * Variables ******************************************************************************/ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /*! @brief Pointers to enet clocks for each instance. */ extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ /******************************************************************************* * Code @@ -62,45 +64,66 @@ 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) { - uint32_t bssReg; uint32_t counter = PHY_TIMEOUT_COUNT; + uint32_t idReg = 0; status_t result = kStatus_Success; uint32_t instance = ENET_GetInstance(base); +#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; + } + /* Reset PHY. */ result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + + 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. */ + 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) { - /* 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)); + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); 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 --) { - /* Check auto negotiation complete. */ - while (counter --) + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); + if ( result == kStatus_Success) { - result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); - if ( result == kStatus_Success) + if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) { - if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) - { - break; - } + break; } + } - if (!counter) - { - return kStatus_PHY_AutoNegotiateFail; - } + if (!counter) + { + return kStatus_PHY_AutoNegotiateFail; } } } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.h b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.h index bf3167fa69..5512477d10 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.h +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/TARGET_FRDM/fsl_phy.h @@ -136,10 +136,19 @@ extern "C" { * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. * @retval kStatus_Success PHY initialize success * @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); +/*! + * @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 * the specified PHY register. This function is called by all PHY interfaces.