Updated PHY KSZ8031
Revision 34:aadfa95d41d2, committed 2018-02-28
- Comitter:
- brdarji
- Date:
- Wed Feb 28 07:22:25 2018 +0000
- Parent:
- 33:44b00841690b
- Commit message:
- STM32f4 ethernet add ; LPC1768 ethernet kSZ8081 added
Changed in this revision
diff -r 44b00841690b -r aadfa95d41d2 arch/TARGET_NXP/lpc_phy_ksz8031.c --- a/arch/TARGET_NXP/lpc_phy_ksz8031.c Fri Jul 08 11:08:53 2016 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,453 +0,0 @@ -/********************************************************************** -* $Id$ lpc_phy_ksz8031.c 2016-1-22 -*//** -* @file lpc_phy_ksz8031.c -* @brief KSZ8031 PHY status and control. -* @version 1.0 -* @date 22 Jan. 2016 -* @author Edutech IoT Team -* -**********************************************************************/ - -#include "lwip/opt.h" -#include "lwip/err.h" -#include "lwip/tcpip.h" -#include "lwip/snmp.h" -#include "lpc_emac_config.h" -#include "lpc_phy.h" -#include "lpc17xx_emac.h" - -/** @defgroup ksz8031_phy PHY status and control for the KSZ8031. - * @ingroup lwip_phy - * - * Various functions for controlling and monitoring the status of the - * KSZ8031 PHY. In polled (standalone) systems, the PHY state must be - * monitored as part of the application. In a threaded (RTOS) system, - * the PHY state is monitored by the PHY handler thread. The MAC - * driver will not transmit unless the PHY link is active. - * @{ - */ - -/** \brief KSZ8031 PHY register offsets */ -#define KSZ_BMCR_REG 0x0 /**< Basic Mode Control Register */ -#define KSZ_BMSR_REG 0x1 /**< Basic Mode Status Reg */ -#define KSZ_IDR1_REG 0x2 /**< Basic Mode Status Reg */ -#define KSZ_IDR2_REG 0x3 /**< Basic Mode Status Reg */ -#define KSZ_ANADV_REG 0x4 /**< Auto_Neg Advt Reg */ -#define KSZ_ANLPA_REG 0x5 /**< Auto_neg Link Partner Ability Reg */ -#define KSZ_ANEEXP_REG 0x6 /**< Auto-neg Expansion Reg */ -#define KSZ_PHY_STAT_REG 0x10 /**< PHY Status Register */ -#define KSZ_PHY_INT_CTL_REG 0x11 /**< PHY Interrupt Control Register */ -#define KSZ_PHY_RBR_REG 0x17 /**< PHY RMII and Bypass Register */ -#define KSZ_PHY_STS_REG 0x19 /**< PHY Status Register */ - -#define KSZ_PHY_SCSR_REG 0x1f /**< PHY Special Control/Status Register (LAN8720) */ - -/** \brief KSZ8031 Control register definitions */ -#define KSZ_RESET (1 << 15) /**< 1= S/W Reset */ -#define KSZ_LOOPBACK (1 << 14) /**< 1=loopback Enabled */ -#define KSZ_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */ -#define KSZ_AUTONEG (3 << 12) /**< 1=Enable auto-negotiation */ -#define KSZ_POWER_DOWN (1 << 11) /**< 1=Power down PHY */ -#define KSZ_ISOLATE (1 << 10) /**< 1=Isolate PHY */ -#define KSZ_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */ -#define KSZ_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */ -#define KSZ_COLLISION_TEST (1 << 7) /**< 1=Perform collsion test */ - -/** \brief KSZ3848 Status register definitions */ -#define KSZ_100BASE_T4 (1 << 15) /**< T4 mode */ -#define KSZ_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */ -#define KSZ_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */ -#define KSZ_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */ -#define KSZ_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */ -#define KSZ_MF_PREAMB_SUPPR (1 << 6) /**< Preamble suppress */ -#define KSZ_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */ -#define KSZ_RMT_FAULT (1 << 4) /**< Fault */ -#define KSZ_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */ -#define KSZ_LINK_STATUS (1 << 2) /**< 1=Link active */ -#define KSZ_JABBER_DETECT (1 << 1) /**< Jabber detect */ -#define KSZ_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */ - -/** \brief KSZ8031 PHY RBR MII dode definitions */ -#define KSZ_RBR_RMII_MODE (1 << 5) /**< Use RMII mode */ - -/** \brief KSZ8031 PHY status definitions */ -#define KSZ_REMOTEFAULT (1 << 6) /**< Remote fault */ -#define KSZ_FULLDUPLEX (1 << 2) /**< 1=full duplex */ -#define KSZ_SPEED10MBPS (1 << 1) /**< 1=10MBps speed */ -#define KSZ_VALID_LINK (1 << 0) /**< 1=Link active */ - -#define KSZ_PHYID1_OUI 0x0022 /**< Expected PHY ID1 */ -#define KSZ_PHYID2_OUI 0x1560 /**< Expected PHY ID2 */ - -/** \brief LAN8720 PHY Special Control/Status Register */ -#define PHY_SCSR_100MBIT 0x0008 /**< Speed: 1=100 MBit, 0=10Mbit */ -#define PHY_SCSR_DUPLEX 0x0010 /**< PHY Duplex Mask */ - -/** \brief Link status bits */ -#define LNK_STAT_VALID 0x01 -#define LNK_STAT_FULLDUPLEX 0x02 -#define LNK_STAT_SPEED10MPS 0x04 - -/** \brief PHY ID definitions */ -#define KSZ8031_ID 0x00221560 /**< PHY Identifier - KSZ8031 */ -#define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */ - -/** \brief PHY status structure used to indicate current status of PHY. - */ -typedef struct { - u32_t phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */ - u32_t phy_full_duplex:1; /**< Half/full duplex connection speed flag. */ - u32_t phy_link_active:1; /**< Phy link active flag. */ -} PHY_STATUS_TYPE; - -/** \brief PHY update flags */ -static PHY_STATUS_TYPE physts; - -/** \brief Last PHY update flags, used for determing if something has changed */ -static PHY_STATUS_TYPE olddphysts; - -/** \brief PHY update counter for state machine */ -static s32_t phyustate; - -/** \brief Holds the PHY ID */ -static u32_t phy_id; - -/** \brief Temporary holder of link status for LAN7420 */ -static u32_t phy_lan7420_sts_tmp; - -/* Write a value via the MII link (non-blocking) */ -void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value) -{ - /* Write value at PHY address and register */ - LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; - LPC_EMAC->MWTD = Value; -} - -/* Write a value via the MII link (blocking) */ -err_t lpc_mii_write(u32_t PhyReg, u32_t Value) -{ - u32_t mst = 250; - err_t sts = ERR_OK; - - /* Write value at PHY address and register */ - lpc_mii_write_noblock(PhyReg, Value); - - /* Wait for unbusy status */ - while (mst > 0) { - sts = LPC_EMAC->MIND; - if ((sts & EMAC_MIND_BUSY) == 0) - mst = 0; - else { - mst--; - osDelay(1); - } - } - - if (sts != 0) - sts = ERR_TIMEOUT; - - return sts; -} - -/* Reads current MII link busy status */ -u32_t lpc_mii_is_busy(void) -{ - return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY); -} - -/* Starts a read operation via the MII link (non-blocking) */ -u32_t lpc_mii_read_data(void) -{ - u32_t data = LPC_EMAC->MRDD; - LPC_EMAC->MCMD = 0; - - return data; -} - -/* Starts a read operation via the MII link (non-blocking) */ -void lpc_mii_read_noblock(u32_t PhyReg) -{ - /* Read value at PHY address and register */ - LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; - LPC_EMAC->MCMD = EMAC_MCMD_READ; -} - -/* Read a value via the MII link (blocking) */ -err_t lpc_mii_read(u32_t PhyReg, u32_t *data) -{ - u32_t mst = 250; - err_t sts = ERR_OK; - - /* Read value at PHY address and register */ - lpc_mii_read_noblock(PhyReg); - - /* Wait for unbusy status */ - while (mst > 0) { - sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL; - if ((sts & EMAC_MIND_BUSY) == 0) { - mst = 0; - *data = LPC_EMAC->MRDD; - } else { - mst--; - osDelay(1); - } - } - - LPC_EMAC->MCMD = 0; - - if (sts != 0) - sts = ERR_TIMEOUT; - - return sts; -} - - -/** \brief Update PHY status from passed value - * - * This function updates the current PHY status based on the - * passed PHY status word. The PHY status indicate if the link - * is active, the connection speed, and duplex. - * - * \param[in] netif NETIF structure - * \param[in] linksts Status word from PHY - * \return 1 if the status has changed, otherwise 0 - */ -static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts) -{ - s32_t changed = 0; - - /* Update link active status */ - if (linksts & LNK_STAT_VALID) - physts.phy_link_active = 1; - else - physts.phy_link_active = 0; - - /* Full or half duplex */ - if (linksts & LNK_STAT_FULLDUPLEX) - physts.phy_full_duplex = 1; - else - physts.phy_full_duplex = 0; - - /* Configure 100MBit/10MBit mode. */ - if (linksts & LNK_STAT_SPEED10MPS) - physts.phy_speed_100mbs = 0; - else - physts.phy_speed_100mbs = 1; - - if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) { - changed = 1; - if (physts.phy_speed_100mbs) { - /* 100MBit mode. */ - lpc_emac_set_speed(1); - - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); - } - else { - /* 10MBit mode. */ - lpc_emac_set_speed(0); - - NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000); - } - - olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs; - } - - if (physts.phy_full_duplex != olddphysts.phy_full_duplex) { - changed = 1; - if (physts.phy_full_duplex) - lpc_emac_set_duplex(1); - else - lpc_emac_set_duplex(0); - - olddphysts.phy_full_duplex = physts.phy_full_duplex; - } - - if (physts.phy_link_active != olddphysts.phy_link_active) { - changed = 1; -#if NO_SYS == 1 - if (physts.phy_link_active) - netif_set_link_up(netif); - else - netif_set_link_down(netif); -#else - if (physts.phy_link_active) - tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up, - (void*) netif, 1); - else - tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down, - (void*) netif, 1); -#endif - - olddphysts.phy_link_active = physts.phy_link_active; - } - - return changed; -} - -/** \brief Initialize the KSZ8031 PHY. - * - * This function initializes the KSZ8031 PHY. It will block until - * complete. This function is called as part of the EMAC driver - * initialization. Configuration of the PHY at startup is - * controlled by setting up configuration defines in lpc_phy.h. - * - * \param[in] netif NETIF structure - * \param[in] rmii If set, configures the PHY for RMII mode - * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT - */ -err_t lpc_phy_init(struct netif *netif, int rmii) -{ - u32_t tmp; - s32_t i; - - physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 0; - physts.phy_full_duplex = olddphysts.phy_full_duplex = 0; - physts.phy_link_active = olddphysts.phy_link_active = 0; - phyustate = 0; - - /* Only first read and write are checked for failure */ - /* Put the KSZ8031 in reset mode and wait for completion */ - if (lpc_mii_write(KSZ_BMCR_REG, KSZ_RESET) != 0) - return ERR_TIMEOUT; - i = 400; - while (i > 0) { - osDelay(1); /* 1 ms */ - if (lpc_mii_read(KSZ_BMCR_REG, &tmp) != 0) - return ERR_TIMEOUT; - - if (!(tmp & (KSZ_RESET | KSZ_POWER_DOWN))) - i = -1; - else - i--; - } - /* Timeout? */ - if (i == 0) - return ERR_TIMEOUT; - - // read PHY ID - lpc_mii_read(KSZ_IDR1_REG, &tmp); - phy_id = (tmp << 16); - lpc_mii_read(KSZ_IDR2_REG, &tmp); - phy_id |= (tmp & 0XFFF0); - - /* Setup link based on configuration options */ -#if PHY_USE_AUTONEG==1 - tmp = KSZ_AUTONEG; -#else - tmp = 0; -#endif -#if PHY_USE_100MBS==1 - tmp |= KSZ_SPEED_SELECT; -#endif -#if PHY_USE_FULL_DUPLEX==1 - tmp |= KSZ_DUPLEX_MODE; -#endif - lpc_mii_write(KSZ_BMCR_REG, tmp); - - /* Wait for autonegotiation completion */ - int j = 1000; - while (j > 0) - { - osDelay(1); // 1 ms - if (lpc_mii_read(KSZ_BMSR_REG, &tmp) != 0) - { - return ERR_TIMEOUT; - } - if (tmp & (KSZ_AUTONEG_COMP)) - j = -1; - else - j--; - } - // Timeout? - if (j == 0) - { - printf("Timeout\n"); - return ERR_TIMEOUT; - } - - /* The link is not set active at this point, but will be detected - later */ - - return ERR_OK; -} - -/* Phy status update state machine */ -s32_t lpc_phy_sts_sm(struct netif *netif) -{ - s32_t changed = 0; - u32_t data = 0; - u32_t tmp,tmp1; - - switch (phyustate) { - default: - case 0: - if (phy_id == KSZ8031_ID) { - lpc_mii_read(KSZ_BMSR_REG, &tmp); - /* To Debug Link Status */ -// if (tmp & LNK_STAT_VALID) -// { -// /* Link is on. */ -// printf("Link is UP\n\r"); -// } - phyustate = 2; - } - else if (phy_id == LAN8720_ID) { - lpc_mii_read_noblock(KSZ_PHY_SCSR_REG); - phyustate = 1; - } - break; - - case 1: - if (phy_id == LAN8720_ID) { - tmp = lpc_mii_read_data(); - // we get speed and duplex here - phy_lan7420_sts_tmp = (tmp & PHY_SCSR_DUPLEX) ? LNK_STAT_FULLDUPLEX : 0; - phy_lan7420_sts_tmp |= (tmp & PHY_SCSR_100MBIT) ? 0 : LNK_STAT_SPEED10MPS; - - //read the status register to get link status - lpc_mii_read_noblock(KSZ_BMSR_REG); - phyustate = 2; - } - break; - - case 2: - /* Wait for read status state */ - if (!lpc_mii_is_busy()) { - /* Update PHY status */ - tmp = lpc_mii_read_data(); - - if (phy_id == KSZ8031_ID) { - // Get autonegotiation complete bit - lpc_mii_read(KSZ_BMSR_REG,&tmp1); - /* To Debug Auto-negotiation */ -// if (tmp1 & KSZ_AUTONEG_COMP) -// { -// /* Auto-negotiation Complete. */ -// printf("Auto-negotiation has completed\n\r"); -// } - // STS register contains all needed status bits - data = (tmp & KSZ_VALID_LINK) ? LNK_STAT_VALID : 0; - data |= (tmp & KSZ_FULLDUPLEX) ? LNK_STAT_FULLDUPLEX : 0; - data |= (tmp & KSZ_SPEED10MBPS) ? LNK_STAT_SPEED10MPS : 0; - } - else if (phy_id == LAN8720_ID) { - // we only get the link status here. - phy_lan7420_sts_tmp |= (tmp & KSZ_LINK_STATUS) ? LNK_STAT_VALID : 0; - data = phy_lan7420_sts_tmp; - } - - changed = lpc_update_phy_sts(netif, data); - phyustate = 0; - } - break; - } - - return changed; -} - -/** - * @} - */ - -/* --------------------------------- End Of File ------------------------------ */
diff -r 44b00841690b -r aadfa95d41d2 arch/TARGET_NXP/lpc_phy_ksz8081.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arch/TARGET_NXP/lpc_phy_ksz8081.c Wed Feb 28 07:22:25 2018 +0000 @@ -0,0 +1,461 @@ +/********************************************************************** +* $Id$ lpc_phy_ksz8031.c 2016-1-22 +*//** +* @file lpc_phy_ksz8031.c +* @brief KSZ8031 PHY status and control. +* @version 1.0 +* @date 22 Jan. 2016 +* @author Edutech IoT Team +* +**********************************************************************/ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/tcpip.h" +#include "lwip/snmp.h" +#include "lpc_emac_config.h" +#include "lpc_phy.h" +#include "lpc17xx_emac.h" + +/** @defgroup ksz8031_phy PHY status and control for the KSZ8031. + * @ingroup lwip_phy + * + * Various functions for controlling and monitoring the status of the + * KSZ8031 PHY. In polled (standalone) systems, the PHY state must be + * monitored as part of the application. In a threaded (RTOS) system, + * the PHY state is monitored by the PHY handler thread. The MAC + * driver will not transmit unless the PHY link is active. + * @{ + */ + +/** \brief KSZ8031 PHY register offsets */ +#define KSZ_BMCR_REG 0x0 /**< Basic Mode Control Register */ +#define KSZ_BMSR_REG 0x1 /**< Basic Mode Status Reg */ +#define KSZ_IDR1_REG 0x2 /**< Basic Mode Status Reg */ +#define KSZ_IDR2_REG 0x3 /**< Basic Mode Status Reg */ +#define KSZ_ANADV_REG 0x4 /**< Auto_Neg Advt Reg */ +#define KSZ_ANLPA_REG 0x5 /**< Auto_neg Link Partner Ability Reg */ +#define KSZ_ANEEXP_REG 0x6 /**< Auto-neg Expansion Reg */ +#define KSZ_PHY_STAT_REG 0x10 /**< PHY Status Register */ +#define KSZ_PHY_INT_CTL_REG 0x11 /**< PHY Interrupt Control Register */ +#define KSZ_PHY_RBR_REG 0x17 /**< PHY RMII and Bypass Register */ +#define KSZ_PHY_STS_REG 0x19 /**< PHY Status Register */ + +#define KSZ_PHY_SCSR_REG 0x1f /**< PHY Special Control/Status Register (LAN8720) */ + +/** \brief KSZ8031 Control register definitions */ +#define KSZ_RESET (1 << 15) /**< 1= S/W Reset */ +#define KSZ_LOOPBACK (1 << 14) /**< 1=loopback Enabled */ +#define KSZ_SPEED_SELECT (1 << 13) /**< 1=Select 100MBps */ +#define KSZ_AUTONEG (3 << 12) /**< 1=Enable auto-negotiation */ +#define KSZ_POWER_DOWN (1 << 11) /**< 1=Power down PHY */ +#define KSZ_ISOLATE (1 << 10) /**< 1=Isolate PHY */ +#define KSZ_RESTART_AUTONEG (1 << 9) /**< 1=Restart auto-negoatiation */ +#define KSZ_DUPLEX_MODE (1 << 8) /**< 1=Full duplex mode */ +#define KSZ_COLLISION_TEST (1 << 7) /**< 1=Perform collsion test */ + +/** \brief KSZ3848 Status register definitions */ +#define KSZ_100BASE_T4 (1 << 15) /**< T4 mode */ +#define KSZ_100BASE_TX_FD (1 << 14) /**< 100MBps full duplex */ +#define KSZ_100BASE_TX_HD (1 << 13) /**< 100MBps half duplex */ +#define KSZ_10BASE_T_FD (1 << 12) /**< 100Bps full duplex */ +#define KSZ_10BASE_T_HD (1 << 11) /**< 10MBps half duplex */ +#define KSZ_MF_PREAMB_SUPPR (1 << 6) /**< Preamble suppress */ +#define KSZ_AUTONEG_COMP (1 << 5) /**< Auto-negotation complete */ +#define KSZ_RMT_FAULT (1 << 4) /**< Fault */ +#define KSZ_AUTONEG_ABILITY (1 << 3) /**< Auto-negotation supported */ +#define KSZ_LINK_STATUS (1 << 2) /**< 1=Link active */ +#define KSZ_JABBER_DETECT (1 << 1) /**< Jabber detect */ +#define KSZ_EXTEND_CAPAB (1 << 0) /**< Supports extended capabilities */ + +/** \brief KSZ8031 PHY RBR MII dode definitions */ +#define KSZ_RBR_RMII_MODE (1 << 5) /**< Use RMII mode */ + +/** \brief KSZ8031 PHY status definitions */ +#define KSZ_REMOTEFAULT (1 << 6) /**< Remote fault */ +#define KSZ_FULLDUPLEX (1 << 2) /**< 1=full duplex */ +#define KSZ_SPEED10MBPS (1 << 1) /**< 1=10MBps speed */ +#define KSZ_VALID_LINK (1 << 0) /**< 1=Link active */ + +//KSZ8081 +#define KSZ_PHYID1_OUI 0x0022 /**< Expected PHY ID1 */ +#define KSZ_PHYID2_OUI 0x1560 /**< Expected PHY ID2 */ + + +//KSZ8031 +//#define KSZ_PHYID1_OUI 0x0022 /**< Expected PHY ID1 */ +//#define KSZ_PHYID2_OUI 0x1550 /**< Expected PHY ID2 */ + + +/** \brief LAN8720 PHY Special Control/Status Register */ +#define PHY_SCSR_100MBIT 0x0008 /**< Speed: 1=100 MBit, 0=10Mbit */ +#define PHY_SCSR_DUPLEX 0x0010 /**< PHY Duplex Mask */ + +/** \brief Link status bits */ +#define LNK_STAT_VALID 0x01 +#define LNK_STAT_FULLDUPLEX 0x02 +#define LNK_STAT_SPEED10MPS 0x04 + +/** \brief PHY ID definitions */ +//#define KSZ8031_ID 0x00221550 /**< PHY Identifier - KSZ8031 */ +#define KSZ8081_ID 0x00221560 /**< PHY Identifier - KSZ8081 */ +#define LAN8720_ID 0x0007C0F0 /**< PHY Identifier - LAN8720 */ + +/** \brief PHY status structure used to indicate current status of PHY. + */ +typedef struct { + u32_t phy_speed_100mbs:1; /**< 10/100 MBS connection speed flag. */ + u32_t phy_full_duplex:1; /**< Half/full duplex connection speed flag. */ + u32_t phy_link_active:1; /**< Phy link active flag. */ +} PHY_STATUS_TYPE; + +/** \brief PHY update flags */ +static PHY_STATUS_TYPE physts; + +/** \brief Last PHY update flags, used for determing if something has changed */ +static PHY_STATUS_TYPE olddphysts; + +/** \brief PHY update counter for state machine */ +static s32_t phyustate; + +/** \brief Holds the PHY ID */ +static u32_t phy_id; + +/** \brief Temporary holder of link status for LAN7420 */ +static u32_t phy_lan7420_sts_tmp; + +/* Write a value via the MII link (non-blocking) */ +void lpc_mii_write_noblock(u32_t PhyReg, u32_t Value) +{ + /* Write value at PHY address and register */ + LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; + LPC_EMAC->MWTD = Value; +} + +/* Write a value via the MII link (blocking) */ +err_t lpc_mii_write(u32_t PhyReg, u32_t Value) +{ + u32_t mst = 250; + err_t sts = ERR_OK; + + /* Write value at PHY address and register */ + lpc_mii_write_noblock(PhyReg, Value); + + /* Wait for unbusy status */ + while (mst > 0) { + sts = LPC_EMAC->MIND; + if ((sts & EMAC_MIND_BUSY) == 0) + mst = 0; + else { + mst--; + osDelay(1); + } + } + + if (sts != 0) + sts = ERR_TIMEOUT; + + return sts; +} + +/* Reads current MII link busy status */ +u32_t lpc_mii_is_busy(void) +{ + return (u32_t) (LPC_EMAC->MIND & EMAC_MIND_BUSY); +} + +/* Starts a read operation via the MII link (non-blocking) */ +u32_t lpc_mii_read_data(void) +{ + u32_t data = LPC_EMAC->MRDD; + LPC_EMAC->MCMD = 0; + + return data; +} + +/* Starts a read operation via the MII link (non-blocking) */ +void lpc_mii_read_noblock(u32_t PhyReg) +{ + /* Read value at PHY address and register */ + LPC_EMAC->MADR = (LPC_PHYDEF_PHYADDR << 8) | PhyReg; + LPC_EMAC->MCMD = EMAC_MCMD_READ; +} + +/* Read a value via the MII link (blocking) */ +err_t lpc_mii_read(u32_t PhyReg, u32_t *data) +{ + u32_t mst = 250; + err_t sts = ERR_OK; + + /* Read value at PHY address and register */ + lpc_mii_read_noblock(PhyReg); + + /* Wait for unbusy status */ + while (mst > 0) { + sts = LPC_EMAC->MIND & ~EMAC_MIND_MII_LINK_FAIL; + if ((sts & EMAC_MIND_BUSY) == 0) { + mst = 0; + *data = LPC_EMAC->MRDD; + } else { + mst--; + osDelay(1); + } + } + + LPC_EMAC->MCMD = 0; + + if (sts != 0) + sts = ERR_TIMEOUT; + + return sts; +} + + +/** \brief Update PHY status from passed value + * + * This function updates the current PHY status based on the + * passed PHY status word. The PHY status indicate if the link + * is active, the connection speed, and duplex. + * + * \param[in] netif NETIF structure + * \param[in] linksts Status word from PHY + * \return 1 if the status has changed, otherwise 0 + */ +static s32_t lpc_update_phy_sts(struct netif *netif, u32_t linksts) +{ + s32_t changed = 0; + + /* Update link active status */ + if (linksts & LNK_STAT_VALID) + physts.phy_link_active = 1; + else + physts.phy_link_active = 0; + + /* Full or half duplex */ + if (linksts & LNK_STAT_FULLDUPLEX) + physts.phy_full_duplex = 1; + else + physts.phy_full_duplex = 0; + + /* Configure 100MBit/10MBit mode. */ + if (linksts & LNK_STAT_SPEED10MPS) + physts.phy_speed_100mbs = 0; + else + physts.phy_speed_100mbs = 1; + + if (physts.phy_speed_100mbs != olddphysts.phy_speed_100mbs) { + changed = 1; + if (physts.phy_speed_100mbs) { + /* 100MBit mode. */ + lpc_emac_set_speed(1); + + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100000000); + } + else { + /* 10MBit mode. */ + lpc_emac_set_speed(0); + + NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 10000000); + } + + olddphysts.phy_speed_100mbs = physts.phy_speed_100mbs; + } + + if (physts.phy_full_duplex != olddphysts.phy_full_duplex) { + changed = 1; + if (physts.phy_full_duplex) + lpc_emac_set_duplex(1); + else + lpc_emac_set_duplex(0); + + olddphysts.phy_full_duplex = physts.phy_full_duplex; + } + + if (physts.phy_link_active != olddphysts.phy_link_active) { + changed = 1; +#if NO_SYS == 1 + if (physts.phy_link_active) + netif_set_link_up(netif); + else + netif_set_link_down(netif); +#else + if (physts.phy_link_active) + tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_up, + (void*) netif, 1); + else + tcpip_callback_with_block((tcpip_callback_fn) netif_set_link_down, + (void*) netif, 1); +#endif + + olddphysts.phy_link_active = physts.phy_link_active; + } + + return changed; +} + +/** \brief Initialize the KSZ8031 PHY. + * + * This function initializes the KSZ8031 PHY. It will block until + * complete. This function is called as part of the EMAC driver + * initialization. Configuration of the PHY at startup is + * controlled by setting up configuration defines in lpc_phy.h. + * + * \param[in] netif NETIF structure + * \param[in] rmii If set, configures the PHY for RMII mode + * \return ERR_OK if the setup was successful, otherwise ERR_TIMEOUT + */ +err_t lpc_phy_init(struct netif *netif, int rmii) +{ + u32_t tmp; + s32_t i; + + physts.phy_speed_100mbs = olddphysts.phy_speed_100mbs = 0; + physts.phy_full_duplex = olddphysts.phy_full_duplex = 0; + physts.phy_link_active = olddphysts.phy_link_active = 0; + phyustate = 0; + + /* Only first read and write are checked for failure */ + /* Put the KSZ8031 in reset mode and wait for completion */ + if (lpc_mii_write(KSZ_BMCR_REG, KSZ_RESET) != 0) + return ERR_TIMEOUT; + i = 400; + while (i > 0) { + osDelay(1); /* 1 ms */ + if (lpc_mii_read(KSZ_BMCR_REG, &tmp) != 0) + return ERR_TIMEOUT; + + if (!(tmp & (KSZ_RESET | KSZ_POWER_DOWN))) + i = -1; + else + i--; + } + /* Timeout? */ + if (i == 0) + return ERR_TIMEOUT; + + // read PHY ID + lpc_mii_read(KSZ_IDR1_REG, &tmp); + phy_id = (tmp << 16); + lpc_mii_read(KSZ_IDR2_REG, &tmp); + phy_id |= (tmp & 0XFFF0); + + /* Setup link based on configuration options */ +#if PHY_USE_AUTONEG==1 + tmp = KSZ_AUTONEG; +#else + tmp = 0; +#endif +#if PHY_USE_100MBS==1 + tmp |= KSZ_SPEED_SELECT; +#endif +#if PHY_USE_FULL_DUPLEX==1 + tmp |= KSZ_DUPLEX_MODE; +#endif + lpc_mii_write(KSZ_BMCR_REG, tmp); + + /* Wait for autonegotiation completion */ + int j = 1000; + while (j > 0) + { + osDelay(1); // 1 ms + if (lpc_mii_read(KSZ_BMSR_REG, &tmp) != 0) + { + return ERR_TIMEOUT; + } + if (tmp & (KSZ_AUTONEG_COMP)) + j = -1; + else + j--; + } + // Timeout? + if (j == 0) + { + printf("Timeout\n"); + return ERR_TIMEOUT; + } + + /* The link is not set active at this point, but will be detected + later */ + + return ERR_OK; +} + +/* Phy status update state machine */ +s32_t lpc_phy_sts_sm(struct netif *netif) +{ + s32_t changed = 0; + u32_t data = 0; + u32_t tmp,tmp1; + + switch (phyustate) { + default: + case 0: + if (phy_id == KSZ8081_ID) { + lpc_mii_read(KSZ_BMSR_REG, &tmp); + /* To Debug Link Status */ +// if (tmp & LNK_STAT_VALID) +// { +// /* Link is on. */ +// printf("Link is UP\n\r"); +// } + phyustate = 2; + } + else if (phy_id == LAN8720_ID) { + lpc_mii_read_noblock(KSZ_PHY_SCSR_REG); + phyustate = 1; + } + break; + + case 1: + if (phy_id == LAN8720_ID) { + tmp = lpc_mii_read_data(); + // we get speed and duplex here + phy_lan7420_sts_tmp = (tmp & PHY_SCSR_DUPLEX) ? LNK_STAT_FULLDUPLEX : 0; + phy_lan7420_sts_tmp |= (tmp & PHY_SCSR_100MBIT) ? 0 : LNK_STAT_SPEED10MPS; + + //read the status register to get link status + lpc_mii_read_noblock(KSZ_BMSR_REG); + phyustate = 2; + } + break; + + case 2: + /* Wait for read status state */ + if (!lpc_mii_is_busy()) { + /* Update PHY status */ + tmp = lpc_mii_read_data(); + + if (phy_id == KSZ8081_ID) { + // Get autonegotiation complete bit + lpc_mii_read(KSZ_BMSR_REG,&tmp1); + /* To Debug Auto-negotiation */ +// if (tmp1 & KSZ_AUTONEG_COMP) +// { +// /* Auto-negotiation Complete. */ +// printf("Auto-negotiation has completed\n\r"); +// } + // STS register contains all needed status bits + data = (tmp & KSZ_VALID_LINK) ? LNK_STAT_VALID : 0; + data |= (tmp & KSZ_FULLDUPLEX) ? LNK_STAT_FULLDUPLEX : 0; + data |= (tmp & KSZ_SPEED10MBPS) ? LNK_STAT_SPEED10MPS : 0; + } + else if (phy_id == LAN8720_ID) { + // we only get the link status here. + phy_lan7420_sts_tmp |= (tmp & KSZ_LINK_STATUS) ? LNK_STAT_VALID : 0; + data = phy_lan7420_sts_tmp; + } + + changed = lpc_update_phy_sts(netif, data); + phyustate = 0; + } + break; + } + + return changed; +} + +/** + * @} + */ + +/* --------------------------------- End Of File ------------------------------ */
diff -r 44b00841690b -r aadfa95d41d2 arch/TARGET_STM/stm32f4_emac.c --- a/arch/TARGET_STM/stm32f4_emac.c Fri Jul 08 11:08:53 2016 +0000 +++ b/arch/TARGET_STM/stm32f4_emac.c Wed Feb 28 07:22:25 2018 +0000 @@ -57,11 +57,14 @@ */ void HAL_ETH_MspInit(ETH_HandleTypeDef* heth) { + uint8_t i=0; + GPIO_InitTypeDef GPIO_InitStruct; if (heth->Instance == ETH) { /* Peripheral clock enable */ __ETH_CLK_ENABLE(); + __GPIOE_CLK_ENABLE(); __GPIOA_CLK_ENABLE(); __GPIOB_CLK_ENABLE(); __GPIOC_CLK_ENABLE(); @@ -76,6 +79,7 @@ PB11 ------> ETH_TX_EN PB12 ------> ETH_TXD0 PB13 ------> ETH_TXD1 + PE2 ------> ETH_RST */ GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; @@ -98,6 +102,18 @@ GPIO_InitStruct.Alternate = GPIO_AF11_ETH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + /*Configure GPIO pin : PE2 */ + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_FAST; + HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); + + HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_RESET); + for (i = 0; i < 100; i++); + HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET); + for (i = 0; i < 100; i++); + /* Peripheral interrupt init*/ /* Sets the priority grouping field */ HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); @@ -181,7 +197,7 @@ heth.Init.AutoNegotiation = ETH_AUTONEGOTIATION_ENABLE; heth.Init.Speed = ETH_SPEED_10M; heth.Init.DuplexMode = ETH_MODE_FULLDUPLEX; - heth.Init.PhyAddress = 1; + heth.Init.PhyAddress = 0; #if (MBED_MAC_ADDRESS_SUM != MBED_MAC_ADDR_INTERFACE) MACAddr[0] = MBED_MAC_ADDR_0; MACAddr[1] = MBED_MAC_ADDR_1;