lpc17xx_emac.c
957 lines
| 31.7 KiB
| text/x-c
|
CLexer
|
r16 | /********************************************************************** | ||
* $Id$ lpc17xx_dac.c 2010-05-21 | ||||
*//** | ||||
* @file lpc17xx_dac.c | ||||
* @brief Contains all functions support for Ethernet MAC firmware | ||||
* library on LPC17xx | ||||
* @version 2.0 | ||||
* @date 21. May. 2010 | ||||
* @author NXP MCU SW Application Team | ||||
* | ||||
* Copyright(C) 2010, NXP Semiconductor | ||||
* All rights reserved. | ||||
* | ||||
*********************************************************************** | ||||
* Software that is described herein is for illustrative purposes only | ||||
* which provides customers with programming information regarding the | ||||
* products. This software is supplied "AS IS" without any warranties. | ||||
* NXP Semiconductors assumes no responsibility or liability for the | ||||
* use of the software, conveys no license or title under any patent, | ||||
* copyright, or mask work right to the product. NXP Semiconductors | ||||
* reserves the right to make changes in the software without | ||||
* notification. NXP Semiconductors also make no representation or | ||||
* warranty that such application will be suitable for the specified | ||||
* use without further testing or modification. | ||||
**********************************************************************/ | ||||
/* Peripheral group ----------------------------------------------------------- */ | ||||
/** @addtogroup EMAC | ||||
* @{ | ||||
*/ | ||||
/* Includes ------------------------------------------------------------------- */ | ||||
#include "lpc17xx_emac.h" | ||||
#include "lpc17xx_clkpwr.h" | ||||
/* If this source file built with example, the LPC17xx FW library configuration | ||||
* file in each example directory ("lpc17xx_libcfg.h") must be included, | ||||
* otherwise the default FW library configuration file must be included instead | ||||
*/ | ||||
#ifdef __BUILD_WITH_EXAMPLE__ | ||||
#include "lpc17xx_libcfg.h" | ||||
#else | ||||
#include "lpc17xx_libcfg_default.h" | ||||
#endif /* __BUILD_WITH_EXAMPLE__ */ | ||||
#ifdef _EMAC | ||||
/* Private Variables ---------------------------------------------------------- */ | ||||
/** @defgroup EMAC_Private_Variables EMAC Private Variables | ||||
* @{ | ||||
*/ | ||||
/* MII Mgmt Configuration register - Clock divider setting */ | ||||
const uint8_t EMAC_clkdiv[] = { 4, 6, 8, 10, 14, 20, 28 }; | ||||
/* EMAC local DMA Descriptors */ | ||||
/** Rx Descriptor data array */ | ||||
static RX_Desc Rx_Desc[EMAC_NUM_RX_FRAG]; | ||||
/** Rx Status data array - Must be 8-Byte aligned */ | ||||
#if defined ( __CC_ARM ) | ||||
static __align(8) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG]; | ||||
#elif defined ( __ICCARM__ ) | ||||
#pragma data_alignment=8 | ||||
static RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG]; | ||||
#elif defined ( __GNUC__ ) | ||||
static __attribute__ ((aligned (8))) RX_Stat Rx_Stat[EMAC_NUM_RX_FRAG]; | ||||
#endif | ||||
/** Tx Descriptor data array */ | ||||
static TX_Desc Tx_Desc[EMAC_NUM_TX_FRAG]; | ||||
/** Tx Status data array */ | ||||
static TX_Stat Tx_Stat[EMAC_NUM_TX_FRAG]; | ||||
/* EMAC local DMA buffers */ | ||||
/** Rx buffer data */ | ||||
static uint32_t rx_buf[EMAC_NUM_RX_FRAG][EMAC_ETH_MAX_FLEN>>2]; | ||||
/** Tx buffer data */ | ||||
static uint32_t tx_buf[EMAC_NUM_TX_FRAG][EMAC_ETH_MAX_FLEN>>2]; | ||||
/** | ||||
* @} | ||||
*/ | ||||
/* Private Functions ---------------------------------------------------------- */ | ||||
static void rx_descr_init (void); | ||||
static void tx_descr_init (void); | ||||
static int32_t write_PHY (uint32_t PhyReg, uint16_t Value); | ||||
static int32_t read_PHY (uint32_t PhyReg); | ||||
static void setEmacAddr(uint8_t abStationAddr[]); | ||||
static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len); | ||||
/*--------------------------- rx_descr_init ---------------------------------*/ | ||||
/*********************************************************************//** | ||||
* @brief Initializes RX Descriptor | ||||
* @param[in] None | ||||
* @return None | ||||
***********************************************************************/ | ||||
static void rx_descr_init (void) | ||||
{ | ||||
/* Initialize Receive Descriptor and Status array. */ | ||||
uint32_t i; | ||||
for (i = 0; i < EMAC_NUM_RX_FRAG; i++) { | ||||
Rx_Desc[i].Packet = (uint32_t)&rx_buf[i]; | ||||
Rx_Desc[i].Ctrl = EMAC_RCTRL_INT | (EMAC_ETH_MAX_FLEN - 1); | ||||
Rx_Stat[i].Info = 0; | ||||
Rx_Stat[i].HashCRC = 0; | ||||
} | ||||
/* Set EMAC Receive Descriptor Registers. */ | ||||
LPC_EMAC->RxDescriptor = (uint32_t)&Rx_Desc[0]; | ||||
LPC_EMAC->RxStatus = (uint32_t)&Rx_Stat[0]; | ||||
LPC_EMAC->RxDescriptorNumber = EMAC_NUM_RX_FRAG - 1; | ||||
/* Rx Descriptors Point to 0 */ | ||||
LPC_EMAC->RxConsumeIndex = 0; | ||||
} | ||||
/*--------------------------- tx_descr_init ---- ----------------------------*/ | ||||
/*********************************************************************//** | ||||
* @brief Initializes TX Descriptor | ||||
* @param[in] None | ||||
* @return None | ||||
***********************************************************************/ | ||||
static void tx_descr_init (void) { | ||||
/* Initialize Transmit Descriptor and Status array. */ | ||||
uint32_t i; | ||||
for (i = 0; i < EMAC_NUM_TX_FRAG; i++) { | ||||
Tx_Desc[i].Packet = (uint32_t)&tx_buf[i]; | ||||
Tx_Desc[i].Ctrl = 0; | ||||
Tx_Stat[i].Info = 0; | ||||
} | ||||
/* Set EMAC Transmit Descriptor Registers. */ | ||||
LPC_EMAC->TxDescriptor = (uint32_t)&Tx_Desc[0]; | ||||
LPC_EMAC->TxStatus = (uint32_t)&Tx_Stat[0]; | ||||
LPC_EMAC->TxDescriptorNumber = EMAC_NUM_TX_FRAG - 1; | ||||
/* Tx Descriptors Point to 0 */ | ||||
LPC_EMAC->TxProduceIndex = 0; | ||||
} | ||||
/*--------------------------- write_PHY -------------------------------------*/ | ||||
/*********************************************************************//** | ||||
* @brief Write value to PHY device | ||||
* @param[in] PhyReg: PHY Register address | ||||
* @param[in] Value: Value to write | ||||
* @return 0 - if success | ||||
* 1 - if fail | ||||
***********************************************************************/ | ||||
static int32_t write_PHY (uint32_t PhyReg, uint16_t Value) | ||||
{ | ||||
/* Write a data 'Value' to PHY register 'PhyReg'. */ | ||||
uint32_t tout; | ||||
LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; | ||||
LPC_EMAC->MWTD = Value; | ||||
/* Wait until operation completed */ | ||||
tout = 0; | ||||
for (tout = 0; tout < EMAC_MII_WR_TOUT; tout++) { | ||||
if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { | ||||
return (0); | ||||
} | ||||
} | ||||
// Time out! | ||||
return (-1); | ||||
} | ||||
/*--------------------------- read_PHY --------------------------------------*/ | ||||
/*********************************************************************//** | ||||
* @brief Read value from PHY device | ||||
* @param[in] PhyReg: PHY Register address | ||||
* @return 0 - if success | ||||
* 1 - if fail | ||||
***********************************************************************/ | ||||
static int32_t read_PHY (uint32_t PhyReg) | ||||
{ | ||||
/* Read a PHY register 'PhyReg'. */ | ||||
uint32_t tout; | ||||
LPC_EMAC->MADR = EMAC_DEF_ADR | PhyReg; | ||||
LPC_EMAC->MCMD = EMAC_MCMD_READ; | ||||
/* Wait until operation completed */ | ||||
tout = 0; | ||||
for (tout = 0; tout < EMAC_MII_RD_TOUT; tout++) { | ||||
if ((LPC_EMAC->MIND & EMAC_MIND_BUSY) == 0) { | ||||
LPC_EMAC->MCMD = 0; | ||||
return (LPC_EMAC->MRDD); | ||||
} | ||||
} | ||||
// Time out! | ||||
return (-1); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Set Station MAC address for EMAC module | ||||
* @param[in] abStationAddr Pointer to Station address that contains 6-bytes | ||||
* of MAC address (should be in order from MAC Address 1 to MAC Address 6) | ||||
* @return None | ||||
**********************************************************************/ | ||||
static void setEmacAddr(uint8_t abStationAddr[]) | ||||
{ | ||||
/* Set the Ethernet MAC Address registers */ | ||||
LPC_EMAC->SA0 = ((uint32_t)abStationAddr[5] << 8) | (uint32_t)abStationAddr[4]; | ||||
LPC_EMAC->SA1 = ((uint32_t)abStationAddr[3] << 8) | (uint32_t)abStationAddr[2]; | ||||
LPC_EMAC->SA2 = ((uint32_t)abStationAddr[1] << 8) | (uint32_t)abStationAddr[0]; | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Calculates CRC code for number of bytes in the frame | ||||
* @param[in] frame_no_fcs Pointer to the first byte of the frame | ||||
* @param[in] frame_len length of the frame without the FCS | ||||
* @return the CRC as a 32 bit integer | ||||
**********************************************************************/ | ||||
static int32_t emac_CRCCalc(uint8_t frame_no_fcs[], int32_t frame_len) | ||||
{ | ||||
int i; // iterator | ||||
int j; // another iterator | ||||
char byte; // current byte | ||||
int crc; // CRC result | ||||
int q0, q1, q2, q3; // temporary variables | ||||
crc = 0xFFFFFFFF; | ||||
for (i = 0; i < frame_len; i++) { | ||||
byte = *frame_no_fcs++; | ||||
for (j = 0; j < 2; j++) { | ||||
if (((crc >> 28) ^ (byte >> 3)) & 0x00000001) { | ||||
q3 = 0x04C11DB7; | ||||
} else { | ||||
q3 = 0x00000000; | ||||
} | ||||
if (((crc >> 29) ^ (byte >> 2)) & 0x00000001) { | ||||
q2 = 0x09823B6E; | ||||
} else { | ||||
q2 = 0x00000000; | ||||
} | ||||
if (((crc >> 30) ^ (byte >> 1)) & 0x00000001) { | ||||
q1 = 0x130476DC; | ||||
} else { | ||||
q1 = 0x00000000; | ||||
} | ||||
if (((crc >> 31) ^ (byte >> 0)) & 0x00000001) { | ||||
q0 = 0x2608EDB8; | ||||
} else { | ||||
q0 = 0x00000000; | ||||
} | ||||
crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0; | ||||
byte >>= 4; | ||||
} | ||||
} | ||||
return crc; | ||||
} | ||||
/* End of Private Functions --------------------------------------------------- */ | ||||
/* Public Functions ----------------------------------------------------------- */ | ||||
/** @addtogroup EMAC_Public_Functions | ||||
* @{ | ||||
*/ | ||||
/*********************************************************************//** | ||||
* @brief Initializes the EMAC peripheral according to the specified | ||||
* parameters in the EMAC_ConfigStruct. | ||||
* @param[in] EMAC_ConfigStruct Pointer to a EMAC_CFG_Type structure | ||||
* that contains the configuration information for the | ||||
* specified EMAC peripheral. | ||||
* @return None | ||||
* | ||||
* Note: This function will initialize EMAC module according to procedure below: | ||||
* - Remove the soft reset condition from the MAC | ||||
* - Configure the PHY via the MIIM interface of the MAC | ||||
* - Select RMII mode | ||||
* - Configure the transmit and receive DMA engines, including the descriptor arrays | ||||
* - Configure the host registers (MAC1,MAC2 etc.) in the MAC | ||||
* - Enable the receive and transmit data paths | ||||
* In default state after initializing, only Rx Done and Tx Done interrupt are enabled, | ||||
* all remain interrupts are disabled | ||||
* (Ref. from LPC17xx UM) | ||||
**********************************************************************/ | ||||
Status EMAC_Init(EMAC_CFG_Type *EMAC_ConfigStruct) | ||||
{ | ||||
/* Initialize the EMAC Ethernet controller. */ | ||||
int32_t regv,tout, tmp; | ||||
/* Set up clock and power for Ethernet module */ | ||||
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, ENABLE); | ||||
/* Reset all EMAC internal modules */ | ||||
LPC_EMAC->MAC1 = EMAC_MAC1_RES_TX | EMAC_MAC1_RES_MCS_TX | EMAC_MAC1_RES_RX | | ||||
EMAC_MAC1_RES_MCS_RX | EMAC_MAC1_SIM_RES | EMAC_MAC1_SOFT_RES; | ||||
LPC_EMAC->Command = EMAC_CR_REG_RES | EMAC_CR_TX_RES | EMAC_CR_RX_RES | EMAC_CR_PASS_RUNT_FRM; | ||||
/* A short delay after reset. */ | ||||
for (tout = 100; tout; tout--); | ||||
/* Initialize MAC control registers. */ | ||||
LPC_EMAC->MAC1 = EMAC_MAC1_PASS_ALL; | ||||
LPC_EMAC->MAC2 = EMAC_MAC2_CRC_EN | EMAC_MAC2_PAD_EN; | ||||
LPC_EMAC->MAXF = EMAC_ETH_MAX_FLEN; | ||||
/* | ||||
* Find the clock that close to desired target clock | ||||
*/ | ||||
tmp = SystemCoreClock / EMAC_MCFG_MII_MAXCLK; | ||||
for (tout = 0; tout < sizeof (EMAC_clkdiv); tout++){ | ||||
if (EMAC_clkdiv[tout] >= tmp) break; | ||||
} | ||||
tout++; | ||||
// Write to MAC configuration register and reset | ||||
LPC_EMAC->MCFG = EMAC_MCFG_CLK_SEL(tout) | EMAC_MCFG_RES_MII; | ||||
// release reset | ||||
LPC_EMAC->MCFG &= ~(EMAC_MCFG_RES_MII); | ||||
LPC_EMAC->CLRT = EMAC_CLRT_DEF; | ||||
LPC_EMAC->IPGR = EMAC_IPGR_P2_DEF; | ||||
/* Enable Reduced MII interface. */ | ||||
LPC_EMAC->Command = EMAC_CR_RMII | EMAC_CR_PASS_RUNT_FRM; | ||||
/* Reset Reduced MII Logic. */ | ||||
LPC_EMAC->SUPP = EMAC_SUPP_RES_RMII; | ||||
for (tout = 100; tout; tout--); | ||||
LPC_EMAC->SUPP = 0; | ||||
/* Put the DP83848C in reset mode */ | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_RESET); | ||||
/* Wait for hardware reset to end. */ | ||||
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { | ||||
regv = read_PHY (EMAC_PHY_REG_BMCR); | ||||
if (!(regv & (EMAC_PHY_BMCR_RESET | EMAC_PHY_BMCR_POWERDOWN))) { | ||||
/* Reset complete, device not Power Down. */ | ||||
break; | ||||
} | ||||
if (tout == 0){ | ||||
// Time out, return ERROR | ||||
return (ERROR); | ||||
} | ||||
} | ||||
// Set PHY mode | ||||
if (EMAC_SetPHYMode(EMAC_ConfigStruct->Mode) < 0){ | ||||
return (ERROR); | ||||
} | ||||
// Set EMAC address | ||||
setEmacAddr(EMAC_ConfigStruct->pbEMAC_Addr); | ||||
/* Initialize Tx and Rx DMA Descriptors */ | ||||
rx_descr_init (); | ||||
tx_descr_init (); | ||||
// Set Receive Filter register: enable broadcast and multicast | ||||
LPC_EMAC->RxFilterCtrl = EMAC_RFC_MCAST_EN | EMAC_RFC_BCAST_EN | EMAC_RFC_PERFECT_EN; | ||||
/* Enable Rx Done and Tx Done interrupt for EMAC */ | ||||
LPC_EMAC->IntEnable = EMAC_INT_RX_DONE | EMAC_INT_TX_DONE; | ||||
/* Reset all interrupts */ | ||||
LPC_EMAC->IntClear = 0xFFFF; | ||||
/* Enable receive and transmit mode of MAC Ethernet core */ | ||||
LPC_EMAC->Command |= (EMAC_CR_RX_EN | EMAC_CR_TX_EN); | ||||
LPC_EMAC->MAC1 |= EMAC_MAC1_REC_EN; | ||||
return SUCCESS; | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief De-initializes the EMAC peripheral registers to their | ||||
* default reset values. | ||||
* @param[in] None | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_DeInit(void) | ||||
{ | ||||
// Disable all interrupt | ||||
LPC_EMAC->IntEnable = 0x00; | ||||
// Clear all pending interrupt | ||||
LPC_EMAC->IntClear = (0xFF) | (EMAC_INT_SOFT_INT | EMAC_INT_WAKEUP); | ||||
/* TurnOff clock and power for Ethernet module */ | ||||
CLKPWR_ConfigPPWR (CLKPWR_PCONP_PCENET, DISABLE); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Check specified PHY status in EMAC peripheral | ||||
* @param[in] ulPHYState Specified PHY Status Type, should be: | ||||
* - EMAC_PHY_STAT_LINK: Link Status | ||||
* - EMAC_PHY_STAT_SPEED: Speed Status | ||||
* - EMAC_PHY_STAT_DUP: Duplex Status | ||||
* @return Status of specified PHY status (0 or 1). | ||||
* (-1) if error. | ||||
* | ||||
* Note: | ||||
* For EMAC_PHY_STAT_LINK, return value: | ||||
* - 0: Link Down | ||||
* - 1: Link Up | ||||
* For EMAC_PHY_STAT_SPEED, return value: | ||||
* - 0: 10Mbps | ||||
* - 1: 100Mbps | ||||
* For EMAC_PHY_STAT_DUP, return value: | ||||
* - 0: Half-Duplex | ||||
* - 1: Full-Duplex | ||||
**********************************************************************/ | ||||
int32_t EMAC_CheckPHYStatus(uint32_t ulPHYState) | ||||
{ | ||||
int32_t regv, tmp; | ||||
#ifdef MCB_LPC_1768 | ||||
regv = read_PHY (EMAC_PHY_REG_STS); | ||||
switch(ulPHYState){ | ||||
case EMAC_PHY_STAT_LINK: | ||||
tmp = (regv & EMAC_PHY_SR_LINK) ? 1 : 0; | ||||
break; | ||||
case EMAC_PHY_STAT_SPEED: | ||||
tmp = (regv & EMAC_PHY_SR_SPEED) ? 0 : 1; | ||||
break; | ||||
case EMAC_PHY_STAT_DUP: | ||||
tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0; | ||||
break; | ||||
#elif defined(IAR_LPC_1768) | ||||
/* Use IAR_LPC_1768 board: | ||||
* FSZ8721BL doesn't have Status Register | ||||
* so we read Basic Mode Status Register (0x01h) instead | ||||
*/ | ||||
regv = read_PHY (EMAC_PHY_REG_BMSR); | ||||
switch(ulPHYState){ | ||||
case EMAC_PHY_STAT_LINK: | ||||
tmp = (regv & EMAC_PHY_BMSR_LINK_STATUS) ? 1 : 0; | ||||
break; | ||||
case EMAC_PHY_STAT_SPEED: | ||||
tmp = (regv & EMAC_PHY_SR_100_SPEED) ? 1 : 0; | ||||
break; | ||||
case EMAC_PHY_STAT_DUP: | ||||
tmp = (regv & EMAC_PHY_SR_FULL_DUP) ? 1 : 0; | ||||
break; | ||||
#endif | ||||
default: | ||||
tmp = -1; | ||||
break; | ||||
} | ||||
return (tmp); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Set specified PHY mode in EMAC peripheral | ||||
* @param[in] ulPHYMode Specified PHY mode, should be: | ||||
* - EMAC_MODE_AUTO | ||||
* - EMAC_MODE_10M_FULL | ||||
* - EMAC_MODE_10M_HALF | ||||
* - EMAC_MODE_100M_FULL | ||||
* - EMAC_MODE_100M_HALF | ||||
* @return Return (0) if no error, otherwise return (-1) | ||||
**********************************************************************/ | ||||
int32_t EMAC_SetPHYMode(uint32_t ulPHYMode) | ||||
{ | ||||
int32_t id1, id2, tout, regv; | ||||
/* Check if this is a DP83848C PHY. */ | ||||
id1 = read_PHY (EMAC_PHY_REG_IDR1); | ||||
id2 = read_PHY (EMAC_PHY_REG_IDR2); | ||||
#ifdef MCB_LPC_1768 | ||||
if (((id1 << 16) | (id2 & 0xFFF0)) == EMAC_DP83848C_ID) { | ||||
switch(ulPHYMode){ | ||||
case EMAC_MODE_AUTO: | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); | ||||
#elif defined(IAR_LPC_1768) /* Use IAR LPC1768 KickStart board */ | ||||
if (((id1 << 16) | id2) == EMAC_KSZ8721BL_ID) { | ||||
/* Configure the PHY device */ | ||||
switch(ulPHYMode){ | ||||
case EMAC_MODE_AUTO: | ||||
/* Use auto-negotiation about the link speed. */ | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_AUTO_NEG); | ||||
// write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_BMCR_AN); | ||||
#endif | ||||
/* Wait to complete Auto_Negotiation */ | ||||
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { | ||||
regv = read_PHY (EMAC_PHY_REG_BMSR); | ||||
if (regv & EMAC_PHY_BMSR_AUTO_DONE) { | ||||
/* Auto-negotiation Complete. */ | ||||
break; | ||||
} | ||||
if (tout == 0){ | ||||
// Time out, return error | ||||
return (-1); | ||||
} | ||||
} | ||||
break; | ||||
case EMAC_MODE_10M_FULL: | ||||
/* Connect at 10MBit full-duplex */ | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_10M); | ||||
break; | ||||
case EMAC_MODE_10M_HALF: | ||||
/* Connect at 10MBit half-duplex */ | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_10M); | ||||
break; | ||||
case EMAC_MODE_100M_FULL: | ||||
/* Connect at 100MBit full-duplex */ | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_FULLD_100M); | ||||
break; | ||||
case EMAC_MODE_100M_HALF: | ||||
/* Connect at 100MBit half-duplex */ | ||||
write_PHY (EMAC_PHY_REG_BMCR, EMAC_PHY_HALFD_100M); | ||||
break; | ||||
default: | ||||
// un-supported | ||||
return (-1); | ||||
} | ||||
} | ||||
// It's not correct module ID | ||||
else { | ||||
return (-1); | ||||
} | ||||
// Update EMAC configuration with current PHY status | ||||
if (EMAC_UpdatePHYStatus() < 0){ | ||||
return (-1); | ||||
} | ||||
// Complete | ||||
return (0); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Auto-Configures value for the EMAC configuration register to | ||||
* match with current PHY mode | ||||
* @param[in] None | ||||
* @return Return (0) if no error, otherwise return (-1) | ||||
* | ||||
* Note: The EMAC configuration will be auto-configured: | ||||
* - Speed mode. | ||||
* - Half/Full duplex mode | ||||
**********************************************************************/ | ||||
int32_t EMAC_UpdatePHYStatus(void) | ||||
{ | ||||
int32_t regv, tout; | ||||
/* Check the link status. */ | ||||
#ifdef MCB_LPC_1768 | ||||
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { | ||||
regv = read_PHY (EMAC_PHY_REG_STS); | ||||
if (regv & EMAC_PHY_SR_LINK) { | ||||
/* Link is on. */ | ||||
break; | ||||
} | ||||
if (tout == 0){ | ||||
// time out | ||||
return (-1); | ||||
} | ||||
} | ||||
/* Configure Full/Half Duplex mode. */ | ||||
if (regv & EMAC_PHY_SR_DUP) { | ||||
/* Full duplex is enabled. */ | ||||
LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; | ||||
LPC_EMAC->Command |= EMAC_CR_FULL_DUP; | ||||
LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; | ||||
} else { | ||||
/* Half duplex mode. */ | ||||
LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; | ||||
} | ||||
if (regv & EMAC_PHY_SR_SPEED) { | ||||
/* 10MBit mode. */ | ||||
LPC_EMAC->SUPP = 0; | ||||
} else { | ||||
/* 100MBit mode. */ | ||||
LPC_EMAC->SUPP = EMAC_SUPP_SPEED; | ||||
} | ||||
#elif defined(IAR_LPC_1768) | ||||
for (tout = EMAC_PHY_RESP_TOUT; tout; tout--) { | ||||
regv = read_PHY (EMAC_PHY_REG_BMSR); | ||||
if (regv & EMAC_PHY_BMSR_LINK_STATUS) { | ||||
/* Link is on. */ | ||||
break; | ||||
} | ||||
if (tout == 0){ | ||||
// time out | ||||
return (-1); | ||||
} | ||||
} | ||||
/* Configure Full/Half Duplex mode. */ | ||||
if (regv & EMAC_PHY_SR_FULL_DUP) { | ||||
/* Full duplex is enabled. */ | ||||
LPC_EMAC->MAC2 |= EMAC_MAC2_FULL_DUP; | ||||
LPC_EMAC->Command |= EMAC_CR_FULL_DUP; | ||||
LPC_EMAC->IPGT = EMAC_IPGT_FULL_DUP; | ||||
} else { | ||||
/* Half duplex mode. */ | ||||
LPC_EMAC->IPGT = EMAC_IPGT_HALF_DUP; | ||||
} | ||||
/* Configure 100MBit/10MBit mode. */ | ||||
if (!(regv & EMAC_PHY_SR_100_SPEED)) { | ||||
/* 10MBit mode. */ | ||||
LPC_EMAC->SUPP = 0; | ||||
} else { | ||||
/* 100MBit mode. */ | ||||
LPC_EMAC->SUPP = EMAC_SUPP_SPEED; | ||||
} | ||||
#endif | ||||
// Complete | ||||
return (0); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Enable/Disable hash filter functionality for specified destination | ||||
* MAC address in EMAC module | ||||
* @param[in] dstMAC_addr Pointer to the first MAC destination address, should | ||||
* be 6-bytes length, in order LSB to the MSB | ||||
* @param[in] NewState New State of this command, should be: | ||||
* - ENABLE. | ||||
* - DISABLE. | ||||
* @return None | ||||
* | ||||
* Note: | ||||
* The standard Ethernet cyclic redundancy check (CRC) function is calculated from | ||||
* the 6 byte destination address in the Ethernet frame (this CRC is calculated | ||||
* anyway as part of calculating the CRC of the whole frame), then bits [28:23] out of | ||||
* the 32 bits CRC result are taken to form the hash. The 6 bit hash is used to access | ||||
* the hash table: it is used as an index in the 64 bit HashFilter register that has been | ||||
* programmed with accept values. If the selected accept value is 1, the frame is | ||||
* accepted. | ||||
**********************************************************************/ | ||||
void EMAC_SetHashFilter(uint8_t dstMAC_addr[], FunctionalState NewState) | ||||
{ | ||||
uint32_t *pReg; | ||||
uint32_t tmp; | ||||
int32_t crc; | ||||
// Calculate the CRC from the destination MAC address | ||||
crc = emac_CRCCalc(dstMAC_addr, 6); | ||||
// Extract the value from CRC to get index value for hash filter table | ||||
crc = (crc >> 23) & 0x3F; | ||||
pReg = (crc > 31) ? ((uint32_t *)&LPC_EMAC->HashFilterH) \ | ||||
: ((uint32_t *)&LPC_EMAC->HashFilterL); | ||||
tmp = (crc > 31) ? (crc - 32) : crc; | ||||
if (NewState == ENABLE) { | ||||
(*pReg) |= (1UL << tmp); | ||||
} else { | ||||
(*pReg) &= ~(1UL << tmp); | ||||
} | ||||
// Enable Rx Filter | ||||
LPC_EMAC->Command &= ~EMAC_CR_PASS_RX_FILT; | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Enable/Disable Filter mode for each specified type EMAC peripheral | ||||
* @param[in] ulFilterMode Filter mode, should be: | ||||
* - EMAC_RFC_UCAST_EN: all frames of unicast types | ||||
* will be accepted | ||||
* - EMAC_RFC_BCAST_EN: broadcast frame will be | ||||
* accepted | ||||
* - EMAC_RFC_MCAST_EN: all frames of multicast | ||||
* types will be accepted | ||||
* - EMAC_RFC_UCAST_HASH_EN: The imperfect hash | ||||
* filter will be applied to unicast addresses | ||||
* - EMAC_RFC_MCAST_HASH_EN: The imperfect hash | ||||
* filter will be applied to multicast addresses | ||||
* - EMAC_RFC_PERFECT_EN: the destination address | ||||
* will be compared with the 6 byte station address | ||||
* programmed in the station address by the filter | ||||
* - EMAC_RFC_MAGP_WOL_EN: the result of the magic | ||||
* packet filter will generate a WoL interrupt when | ||||
* there is a match | ||||
* - EMAC_RFC_PFILT_WOL_EN: the result of the perfect address | ||||
* matching filter and the imperfect hash filter will | ||||
* generate a WoL interrupt when there is a match | ||||
* @param[in] NewState New State of this command, should be: | ||||
* - ENABLE | ||||
* - DISABLE | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_SetFilterMode(uint32_t ulFilterMode, FunctionalState NewState) | ||||
{ | ||||
if (NewState == ENABLE){ | ||||
LPC_EMAC->RxFilterCtrl |= ulFilterMode; | ||||
} else { | ||||
LPC_EMAC->RxFilterCtrl &= ~ulFilterMode; | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Get status of Wake On LAN Filter for each specified | ||||
* type in EMAC peripheral, clear this status if it is set | ||||
* @param[in] ulWoLMode WoL Filter mode, should be: | ||||
* - EMAC_WOL_UCAST: unicast frames caused WoL | ||||
* - EMAC_WOL_UCAST: broadcast frame caused WoL | ||||
* - EMAC_WOL_MCAST: multicast frame caused WoL | ||||
* - EMAC_WOL_UCAST_HASH: unicast frame that passes the | ||||
* imperfect hash filter caused WoL | ||||
* - EMAC_WOL_MCAST_HASH: multicast frame that passes the | ||||
* imperfect hash filter caused WoL | ||||
* - EMAC_WOL_PERFECT:perfect address matching filter | ||||
* caused WoL | ||||
* - EMAC_WOL_RX_FILTER: the receive filter caused WoL | ||||
* - EMAC_WOL_MAG_PACKET: the magic packet filter caused WoL | ||||
* @return SET/RESET | ||||
**********************************************************************/ | ||||
FlagStatus EMAC_GetWoLStatus(uint32_t ulWoLMode) | ||||
{ | ||||
if (LPC_EMAC->RxFilterWoLStatus & ulWoLMode) { | ||||
LPC_EMAC->RxFilterWoLClear = ulWoLMode; | ||||
return SET; | ||||
} else { | ||||
return RESET; | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Write data to Tx packet data buffer at current index due to | ||||
* TxProduceIndex | ||||
* @param[in] pDataStruct Pointer to a EMAC_PACKETBUF_Type structure | ||||
* data that contain specified information about | ||||
* Packet data buffer. | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_WritePacketBuffer(EMAC_PACKETBUF_Type *pDataStruct) | ||||
{ | ||||
uint32_t idx,len; | ||||
uint32_t *sp,*dp; | ||||
idx = LPC_EMAC->TxProduceIndex; | ||||
sp = (uint32_t *)pDataStruct->pbDataBuf; | ||||
dp = (uint32_t *)Tx_Desc[idx].Packet; | ||||
/* Copy frame data to EMAC packet buffers. */ | ||||
for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) { | ||||
*dp++ = *sp++; | ||||
} | ||||
Tx_Desc[idx].Ctrl = (pDataStruct->ulDataLen - 1) | (EMAC_TCTRL_INT | EMAC_TCTRL_LAST); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Read data from Rx packet data buffer at current index due | ||||
* to RxConsumeIndex | ||||
* @param[in] pDataStruct Pointer to a EMAC_PACKETBUF_Type structure | ||||
* data that contain specified information about | ||||
* Packet data buffer. | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_ReadPacketBuffer(EMAC_PACKETBUF_Type *pDataStruct) | ||||
{ | ||||
uint32_t idx, len; | ||||
uint32_t *dp, *sp; | ||||
idx = LPC_EMAC->RxConsumeIndex; | ||||
dp = (uint32_t *)pDataStruct->pbDataBuf; | ||||
sp = (uint32_t *)Rx_Desc[idx].Packet; | ||||
if (pDataStruct->pbDataBuf != NULL) { | ||||
for (len = (pDataStruct->ulDataLen + 3) >> 2; len; len--) { | ||||
*dp++ = *sp++; | ||||
} | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Enable/Disable interrupt for each type in EMAC | ||||
* @param[in] ulIntType Interrupt Type, should be: | ||||
* - EMAC_INT_RX_OVERRUN: Receive Overrun | ||||
* - EMAC_INT_RX_ERR: Receive Error | ||||
* - EMAC_INT_RX_FIN: Receive Descriptor Finish | ||||
* - EMAC_INT_RX_DONE: Receive Done | ||||
* - EMAC_INT_TX_UNDERRUN: Transmit Under-run | ||||
* - EMAC_INT_TX_ERR: Transmit Error | ||||
* - EMAC_INT_TX_FIN: Transmit descriptor finish | ||||
* - EMAC_INT_TX_DONE: Transmit Done | ||||
* - EMAC_INT_SOFT_INT: Software interrupt | ||||
* - EMAC_INT_WAKEUP: Wakeup interrupt | ||||
* @param[in] NewState New State of this function, should be: | ||||
* - ENABLE. | ||||
* - DISABLE. | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_IntCmd(uint32_t ulIntType, FunctionalState NewState) | ||||
{ | ||||
if (NewState == ENABLE) { | ||||
LPC_EMAC->IntEnable |= ulIntType; | ||||
} else { | ||||
LPC_EMAC->IntEnable &= ~(ulIntType); | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Check whether if specified interrupt flag is set or not | ||||
* for each interrupt type in EMAC and clear interrupt pending | ||||
* if it is set. | ||||
* @param[in] ulIntType Interrupt Type, should be: | ||||
* - EMAC_INT_RX_OVERRUN: Receive Overrun | ||||
* - EMAC_INT_RX_ERR: Receive Error | ||||
* - EMAC_INT_RX_FIN: Receive Descriptor Finish | ||||
* - EMAC_INT_RX_DONE: Receive Done | ||||
* - EMAC_INT_TX_UNDERRUN: Transmit Under-run | ||||
* - EMAC_INT_TX_ERR: Transmit Error | ||||
* - EMAC_INT_TX_FIN: Transmit descriptor finish | ||||
* - EMAC_INT_TX_DONE: Transmit Done | ||||
* - EMAC_INT_SOFT_INT: Software interrupt | ||||
* - EMAC_INT_WAKEUP: Wakeup interrupt | ||||
* @return New state of specified interrupt (SET or RESET) | ||||
**********************************************************************/ | ||||
IntStatus EMAC_IntGetStatus(uint32_t ulIntType) | ||||
{ | ||||
if (LPC_EMAC->IntStatus & ulIntType) { | ||||
LPC_EMAC->IntClear = ulIntType; | ||||
return SET; | ||||
} else { | ||||
return RESET; | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Check whether if the current RxConsumeIndex is not equal to the | ||||
* current RxProduceIndex. | ||||
* @param[in] None | ||||
* @return TRUE if they're not equal, otherwise return FALSE | ||||
* | ||||
* Note: In case the RxConsumeIndex is not equal to the RxProduceIndex, | ||||
* it means there're available data has been received. They should be read | ||||
* out and released the Receive Data Buffer by updating the RxConsumeIndex value. | ||||
**********************************************************************/ | ||||
Bool EMAC_CheckReceiveIndex(void) | ||||
{ | ||||
if (LPC_EMAC->RxConsumeIndex != LPC_EMAC->RxProduceIndex) { | ||||
return TRUE; | ||||
} else { | ||||
return FALSE; | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Check whether if the current TxProduceIndex is not equal to the | ||||
* current RxProduceIndex - 1. | ||||
* @param[in] None | ||||
* @return TRUE if they're not equal, otherwise return FALSE | ||||
* | ||||
* Note: In case the RxConsumeIndex is equal to the RxProduceIndex - 1, | ||||
* it means the transmit buffer is available and data can be written to transmit | ||||
* buffer to be sent. | ||||
**********************************************************************/ | ||||
Bool EMAC_CheckTransmitIndex(void) | ||||
{ | ||||
uint32_t tmp = LPC_EMAC->TxConsumeIndex -1; | ||||
if (LPC_EMAC->TxProduceIndex == tmp) { | ||||
return FALSE; | ||||
} else { | ||||
return TRUE; | ||||
} | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Get current status value of receive data (due to RxConsumeIndex) | ||||
* @param[in] ulRxStatType Received Status type, should be one of following: | ||||
* - EMAC_RINFO_CTRL_FRAME: Control Frame | ||||
* - EMAC_RINFO_VLAN: VLAN Frame | ||||
* - EMAC_RINFO_FAIL_FILT: RX Filter Failed | ||||
* - EMAC_RINFO_MCAST: Multicast Frame | ||||
* - EMAC_RINFO_BCAST: Broadcast Frame | ||||
* - EMAC_RINFO_CRC_ERR: CRC Error in Frame | ||||
* - EMAC_RINFO_SYM_ERR: Symbol Error from PHY | ||||
* - EMAC_RINFO_LEN_ERR: Length Error | ||||
* - EMAC_RINFO_RANGE_ERR: Range error(exceeded max size) | ||||
* - EMAC_RINFO_ALIGN_ERR: Alignment error | ||||
* - EMAC_RINFO_OVERRUN: Receive overrun | ||||
* - EMAC_RINFO_NO_DESCR: No new Descriptor available | ||||
* - EMAC_RINFO_LAST_FLAG: last Fragment in Frame | ||||
* - EMAC_RINFO_ERR: Error Occurred (OR of all error) | ||||
* @return Current value of receive data (due to RxConsumeIndex) | ||||
**********************************************************************/ | ||||
FlagStatus EMAC_CheckReceiveDataStatus(uint32_t ulRxStatType) | ||||
{ | ||||
uint32_t idx; | ||||
idx = LPC_EMAC->RxConsumeIndex; | ||||
return (((Rx_Stat[idx].Info) & ulRxStatType) ? SET : RESET); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Get size of current Received data in received buffer (due to | ||||
* RxConsumeIndex) | ||||
* @param[in] None | ||||
* @return Size of received data | ||||
**********************************************************************/ | ||||
uint32_t EMAC_GetReceiveDataSize(void) | ||||
{ | ||||
uint32_t idx; | ||||
idx =LPC_EMAC->RxConsumeIndex; | ||||
return ((Rx_Stat[idx].Info) & EMAC_RINFO_SIZE); | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Increase the RxConsumeIndex (after reading the Receive buffer | ||||
* to release the Receive buffer) and wrap-around the index if | ||||
* it reaches the maximum Receive Number | ||||
* @param[in] None | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_UpdateRxConsumeIndex(void) | ||||
{ | ||||
// Get current Rx consume index | ||||
uint32_t idx = LPC_EMAC->RxConsumeIndex; | ||||
/* Release frame from EMAC buffer */ | ||||
if (++idx == EMAC_NUM_RX_FRAG) idx = 0; | ||||
LPC_EMAC->RxConsumeIndex = idx; | ||||
} | ||||
/*********************************************************************//** | ||||
* @brief Increase the TxProduceIndex (after writting to the Transmit buffer | ||||
* to enable the Transmit buffer) and wrap-around the index if | ||||
* it reaches the maximum Transmit Number | ||||
* @param[in] None | ||||
* @return None | ||||
**********************************************************************/ | ||||
void EMAC_UpdateTxProduceIndex(void) | ||||
{ | ||||
// Get current Tx produce index | ||||
uint32_t idx = LPC_EMAC->TxProduceIndex; | ||||
/* Start frame transmission */ | ||||
if (++idx == EMAC_NUM_TX_FRAG) idx = 0; | ||||
LPC_EMAC->TxProduceIndex = idx; | ||||
} | ||||
/** | ||||
* @} | ||||
*/ | ||||
#endif /* _EMAC */ | ||||
/** | ||||
* @} | ||||
*/ | ||||
/* --------------------------------- End Of File ------------------------------ */ | ||||