mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #12991 from OpenNuvoton/nuvoton_emac_bus_err
Nuvoton: Support EMAC bus reset as while bus errpull/13069/head
commit
096b3e80ec
|
|
@ -16,24 +16,30 @@
|
|||
*
|
||||
* Description: M480 MAC driver source file
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "m480_eth.h"
|
||||
#include "mbed_toolchain.h"
|
||||
//#define NU_TRACE
|
||||
#include "numaker_eth_hal.h"
|
||||
|
||||
#define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0)
|
||||
#define ETH_TRIGGER_TX() do{EMAC->TXST = 0;}while(0)
|
||||
#define ETH_ENABLE_TX() do{EMAC->CTL |= EMAC_CTL_TXON;}while(0)
|
||||
#define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON;}while(0)
|
||||
#define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON_Msk;}while(0)
|
||||
#define ETH_DISABLE_TX() do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0)
|
||||
#define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0)
|
||||
#define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON_Msk;}while(0)
|
||||
|
||||
#define EMAC_ENABLE_INT(emac, u32eIntSel) ((emac)->INTEN |= (u32eIntSel))
|
||||
#define EMAC_DISABLE_INT(emac, u32eIntSel) ((emac)->INTEN &= ~ (u32eIntSel))
|
||||
|
||||
MBED_ALIGN(4) struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
|
||||
MBED_ALIGN(4) struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
|
||||
|
||||
struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
|
||||
|
||||
__attribute__((section("EMAC_RAM")))
|
||||
MBED_ALIGN(4) uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
|
||||
__attribute__((section("EMAC_RAM")))
|
||||
MBED_ALIGN(4) uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
|
||||
|
||||
eth_callback_t nu_eth_txrx_cb = NULL;
|
||||
|
|
@ -41,6 +47,9 @@ void *nu_userData = NULL;
|
|||
|
||||
extern void ack_emac_rx_isr(void);
|
||||
|
||||
static bool isPhyReset = false;
|
||||
static uint16_t phyLPAval = 0;
|
||||
|
||||
// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
|
||||
// Assume we want to set each tick to 100ns.
|
||||
// Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
|
||||
|
|
@ -80,8 +89,9 @@ static int reset_phy(void)
|
|||
delayCnt = 2000;
|
||||
while (delayCnt > 0) {
|
||||
delayCnt--;
|
||||
if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)
|
||||
if ((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -103,9 +113,10 @@ static int reset_phy(void)
|
|||
while (delayCnt > 0) {
|
||||
delayCnt--;
|
||||
if ((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
|
||||
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
|
||||
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (delayCnt == 0) {
|
||||
NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
|
||||
|
|
@ -113,6 +124,7 @@ static int reset_phy(void)
|
|||
return (-1);
|
||||
} else {
|
||||
reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
|
||||
phyLPAval = reg;
|
||||
|
||||
if (reg & ADVERTISE_100FULL) {
|
||||
NU_DEBUGF(("100 full\n"));
|
||||
|
|
@ -164,7 +176,7 @@ static void init_rx_desc(void)
|
|||
rx_desc[i].status1 = OWNERSHIP_EMAC;
|
||||
rx_desc[i].buf = &rx_buf[i][0];
|
||||
rx_desc[i].status2 = 0;
|
||||
rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
|
||||
rx_desc[i].next = &rx_desc[(i + 1) % RX_DESCRIPTOR_NUM];
|
||||
}
|
||||
EMAC->RXDSA = (unsigned int)&rx_desc[0];
|
||||
return;
|
||||
|
|
@ -263,10 +275,31 @@ void numaker_eth_init(uint8_t *mac_addr)
|
|||
EMAC_CAMCTL_AMP_Msk |
|
||||
EMAC_CAMCTL_ABP_Msk;
|
||||
EMAC->CAMEN = 1; // Enable CAM entry 0
|
||||
|
||||
/* Limit the max receive frame length to 1514 + 4 */
|
||||
EMAC->MRFL = NU_ETH_MAX_FLEN;
|
||||
reset_phy();
|
||||
|
||||
/* Set RX FIFO threshold as 8 words */
|
||||
EMAC->FIFOCTL = 0x00200100;
|
||||
|
||||
if (isPhyReset != true) {
|
||||
if (!reset_phy()) {
|
||||
isPhyReset = true;
|
||||
}
|
||||
} else {
|
||||
if (phyLPAval & ADVERTISE_100FULL) {
|
||||
NU_DEBUGF(("100 full\n"));
|
||||
EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
|
||||
} else if (phyLPAval & ADVERTISE_100HALF) {
|
||||
NU_DEBUGF(("100 half\n"));
|
||||
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
|
||||
} else if (phyLPAval & ADVERTISE_10FULL) {
|
||||
NU_DEBUGF(("10 full\n"));
|
||||
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
|
||||
} else {
|
||||
NU_DEBUGF(("10 half\n"));
|
||||
EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
EMAC_ENABLE_RX();
|
||||
EMAC_ENABLE_TX();
|
||||
|
|
@ -285,20 +318,26 @@ unsigned int m_status;
|
|||
|
||||
void EMAC_RX_IRQHandler(void)
|
||||
{
|
||||
// NU_DEBUGF(("%s ... nu_eth_txrx_cb=0x%x\r\n", __FUNCTION__, nu_eth_txrx_cb));
|
||||
m_status = EMAC->INTSTS & 0xFFFF;
|
||||
EMAC->INTSTS = m_status;
|
||||
if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
|
||||
// Shouldn't goes here, unless descriptor corrupted
|
||||
NU_DEBUGF(("RX descriptor corrupted \r\n"));
|
||||
//return;
|
||||
mbed_error_printf("### RX Bus error [0x%x]\r\n", m_status);
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('B', nu_userData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
EMAC_DISABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('R', nu_userData);
|
||||
}
|
||||
if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('R', nu_userData);
|
||||
}
|
||||
|
||||
|
||||
void numaker_eth_trigger_rx(void)
|
||||
{
|
||||
EMAC_ENABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
|
||||
ETH_TRIGGER_RX();
|
||||
}
|
||||
|
||||
|
|
@ -307,16 +346,26 @@ int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
|
|||
unsigned int cur_entry, status;
|
||||
|
||||
cur_entry = EMAC->CRXDSA;
|
||||
if ((cur_entry == (uint32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) // cur_entry may equal to cur_rx_desc_ptr if RDU occures
|
||||
if ((cur_entry == (uint32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) { // cur_entry may equal to cur_rx_desc_ptr if RDU occures
|
||||
return -1;
|
||||
}
|
||||
status = cur_rx_desc_ptr->status1;
|
||||
|
||||
if(status & OWNERSHIP_EMAC)
|
||||
if (status & OWNERSHIP_EMAC) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status & RXFD_RXGD) {
|
||||
*buf = cur_rx_desc_ptr->buf;
|
||||
*len = status & 0xFFFF;
|
||||
// length of payload should be <= 1514
|
||||
if (*len > (NU_ETH_MAX_FLEN - 4)) {
|
||||
NU_DEBUGF(("%s... unexpected long packet length=%d, buf=0x%x\r\n", __FUNCTION__, *len, *buf));
|
||||
*len = 0; // Skip this unexpected long packet
|
||||
}
|
||||
if (*len == (NU_ETH_MAX_FLEN - 4)) {
|
||||
NU_DEBUGF(("%s... length=%d, buf=0x%x\r\n", __FUNCTION__, *len, *buf));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -335,6 +384,10 @@ void EMAC_TX_IRQHandler(void)
|
|||
EMAC->INTSTS = status;
|
||||
if (status & EMAC_INTSTS_TXBEIF_Msk) {
|
||||
// Shouldn't goes here, unless descriptor corrupted
|
||||
mbed_error_printf("### TX Bus error [0x%x]\r\n", status);
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('B', nu_userData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -345,16 +398,19 @@ void EMAC_TX_IRQHandler(void)
|
|||
fin_tx_desc_ptr = fin_tx_desc_ptr->next;
|
||||
}
|
||||
|
||||
if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('T', nu_userData);
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('T', nu_userData);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *numaker_eth_get_tx_buf(void)
|
||||
{
|
||||
if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
|
||||
if (cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC) {
|
||||
return (NULL);
|
||||
else
|
||||
} else {
|
||||
return (cur_tx_desc_ptr->buf);
|
||||
}
|
||||
}
|
||||
|
||||
void numaker_eth_trigger_tx(uint16_t length, void *p)
|
||||
{
|
||||
|
|
@ -372,8 +428,9 @@ int numaker_eth_link_ok(void)
|
|||
{
|
||||
/* first, a dummy read to latch */
|
||||
mdio_read(CONFIG_PHY_ADDR, MII_BMSR);
|
||||
if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS)
|
||||
if (mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -396,8 +453,7 @@ void mbed_mac_address(char *mac)
|
|||
// http://en.wikipedia.org/wiki/MAC_address
|
||||
uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800
|
||||
|
||||
if( word0 == 0xFFFFFFFF ) // Not burn any mac address at 1st 2 words of Data Flash
|
||||
{
|
||||
if (word0 == 0xFFFFFFFF) { // Not burn any mac address at 1st 2 words of Data Flash
|
||||
// with a semi-unique MAC address from the UUID
|
||||
/* Enable FMC ISP function */
|
||||
SYS_UnlockReg();
|
||||
|
|
@ -425,14 +481,16 @@ void mbed_mac_address(char *mac)
|
|||
NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
|
||||
}
|
||||
|
||||
void numaker_eth_enable_interrupts(void) {
|
||||
void numaker_eth_enable_interrupts(void)
|
||||
{
|
||||
EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
|
||||
EMAC_INTEN_TXIEN_Msk ;
|
||||
NVIC_EnableIRQ(EMAC_RX_IRQn);
|
||||
NVIC_EnableIRQ(EMAC_TX_IRQn);
|
||||
}
|
||||
|
||||
void numaker_eth_disable_interrupts(void) {
|
||||
void numaker_eth_disable_interrupts(void)
|
||||
{
|
||||
NVIC_DisableIRQ(EMAC_RX_IRQn);
|
||||
NVIC_DisableIRQ(EMAC_TX_IRQn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,30 +16,38 @@
|
|||
*
|
||||
* Description: NUC472 MAC driver source file
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include "nuc472_eth.h"
|
||||
#include "mbed_toolchain.h"
|
||||
//#define NU_TRACE
|
||||
#include "numaker_eth_hal.h"
|
||||
|
||||
#define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0)
|
||||
#define ETH_TRIGGER_TX() do{EMAC->TXST = 0;}while(0)
|
||||
#define ETH_ENABLE_TX() do{EMAC->CTL |= EMAC_CTL_TXON;}while(0)
|
||||
#define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON;}while(0)
|
||||
#define ETH_ENABLE_RX() do{EMAC->CTL |= EMAC_CTL_RXON_Msk;}while(0)
|
||||
#define ETH_DISABLE_TX() do{EMAC->CTL &= ~EMAC_CTL_TXON;}while(0)
|
||||
#define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON;}while(0)
|
||||
#define ETH_DISABLE_RX() do{EMAC->CTL &= ~EMAC_CTL_RXON_Msk;}while(0)
|
||||
|
||||
#define EMAC_ENABLE_INT(emac, u32eIntSel) ((emac)->INTEN |= (u32eIntSel))
|
||||
#define EMAC_DISABLE_INT(emac, u32eIntSel) ((emac)->INTEN &= ~ (u32eIntSel))
|
||||
|
||||
MBED_ALIGN(4) struct eth_descriptor rx_desc[RX_DESCRIPTOR_NUM];
|
||||
MBED_ALIGN(4) struct eth_descriptor tx_desc[TX_DESCRIPTOR_NUM];
|
||||
|
||||
struct eth_descriptor volatile *cur_tx_desc_ptr, *cur_rx_desc_ptr, *fin_tx_desc_ptr;
|
||||
|
||||
__attribute__((section("EMAC_RAM")))
|
||||
MBED_ALIGN(4) uint8_t rx_buf[RX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
|
||||
__attribute__((section("EMAC_RAM")))
|
||||
MBED_ALIGN(4) uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
|
||||
|
||||
eth_callback_t nu_eth_txrx_cb = NULL;
|
||||
void *nu_userData = NULL;
|
||||
|
||||
extern void ack_emac_rx_isr(void);
|
||||
static bool isPhyReset = false;
|
||||
static uint16_t phyLPAval = 0;
|
||||
|
||||
// PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
|
||||
// Assume we want to set each tick to 100ns.
|
||||
|
|
@ -80,8 +88,9 @@ static int reset_phy(void)
|
|||
delayCnt = 2000;
|
||||
while (delayCnt > 0) {
|
||||
delayCnt--;
|
||||
if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0)
|
||||
if ((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -103,9 +112,10 @@ static int reset_phy(void)
|
|||
while (delayCnt > 0) {
|
||||
delayCnt--;
|
||||
if ((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
|
||||
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
|
||||
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (delayCnt == 0) {
|
||||
NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
|
||||
|
|
@ -113,6 +123,7 @@ static int reset_phy(void)
|
|||
return (-1);
|
||||
} else {
|
||||
reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
|
||||
phyLPAval = reg;
|
||||
|
||||
if (reg & ADVERTISE_100FULL) {
|
||||
NU_DEBUGF(("100 full\n"));
|
||||
|
|
@ -164,7 +175,7 @@ static void init_rx_desc(void)
|
|||
rx_desc[i].status1 = OWNERSHIP_EMAC;
|
||||
rx_desc[i].buf = &rx_buf[i][0];
|
||||
rx_desc[i].status2 = 0;
|
||||
rx_desc[i].next = &rx_desc[(i + 1) % TX_DESCRIPTOR_NUM];
|
||||
rx_desc[i].next = &rx_desc[(i + 1) % (RX_DESCRIPTOR_NUM)];
|
||||
}
|
||||
EMAC->RXDSA = (unsigned int)&rx_desc[0];
|
||||
return;
|
||||
|
|
@ -188,10 +199,14 @@ void numaker_set_mac_addr(uint8_t *addr)
|
|||
|
||||
static void __eth_clk_pin_init()
|
||||
{
|
||||
/* Unlock protected registers */
|
||||
SYS_UnlockReg();
|
||||
/* Enable IP clock */
|
||||
CLK_EnableModuleClock(EMAC_MODULE);
|
||||
// Configure MDC clock rate to HCLK / (127 + 1) = 656 kHz if system is running at 84 MHz
|
||||
CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
|
||||
/* Update System Core Clock */
|
||||
SystemCoreClockUpdate();
|
||||
/*---------------------------------------------------------------------------------------------------------*/
|
||||
/* Init I/O Multi-function */
|
||||
/*---------------------------------------------------------------------------------------------------------*/
|
||||
|
|
@ -216,6 +231,8 @@ static void __eth_clk_pin_init()
|
|||
SYS->GPB_MFPH &= ~(SYS_GPB_MFPH_PB14MFP_Msk | SYS_GPB_MFPH_PB15MFP_Msk);
|
||||
SYS->GPB_MFPH |= SYS_GPB_MFPH_PB14MFP_EMAC_MII_MDC | SYS_GPB_MFPH_PB15MFP_EMAC_MII_MDIO;
|
||||
|
||||
/* Lock protected registers */
|
||||
SYS_LockReg();
|
||||
}
|
||||
|
||||
void numaker_eth_init(uint8_t *mac_addr)
|
||||
|
|
@ -225,15 +242,13 @@ void numaker_eth_init(uint8_t *mac_addr)
|
|||
|
||||
// Reset MAC
|
||||
EMAC->CTL = EMAC_CTL_RST_Msk;
|
||||
while (EMAC->CTL & EMAC_CTL_RST_Msk) {}
|
||||
|
||||
init_tx_desc();
|
||||
init_rx_desc();
|
||||
|
||||
numaker_set_mac_addr(mac_addr); // need to reconfigure hardware address 'cos we just RESET emc...
|
||||
|
||||
/* Limit the max receive frame length to 1514 + 4 */
|
||||
EMAC->MRFL = NU_ETH_MAX_FLEN;
|
||||
reset_phy();
|
||||
|
||||
EMAC->CTL |= EMAC_CTL_STRIPCRC_Msk | EMAC_CTL_RXON_Msk | EMAC_CTL_TXON_Msk | EMAC_CTL_RMIIEN_Msk | EMAC_CTL_RMIIRXCTL_Msk;
|
||||
EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
|
||||
|
|
@ -244,7 +259,34 @@ void numaker_eth_init(uint8_t *mac_addr)
|
|||
EMAC_INTEN_TXABTIEN_Msk |
|
||||
EMAC_INTEN_TXCPIEN_Msk |
|
||||
EMAC_INTEN_TXBEIEN_Msk;
|
||||
EMAC->RXST = 0; // trigger Rx
|
||||
/* Limit the max receive frame length to 1514 + 4 */
|
||||
EMAC->MRFL = NU_ETH_MAX_FLEN;
|
||||
|
||||
/* Set RX FIFO threshold as 8 words */
|
||||
|
||||
if (isPhyReset != true) {
|
||||
if (!reset_phy()) {
|
||||
isPhyReset = true;
|
||||
}
|
||||
} else {
|
||||
if (phyLPAval & ADVERTISE_100FULL) {
|
||||
NU_DEBUGF(("100 full\n"));
|
||||
EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
|
||||
} else if (phyLPAval & ADVERTISE_100HALF) {
|
||||
NU_DEBUGF(("100 half\n"));
|
||||
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
|
||||
} else if (phyLPAval & ADVERTISE_10FULL) {
|
||||
NU_DEBUGF(("10 full\n"));
|
||||
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
|
||||
} else {
|
||||
NU_DEBUGF(("10 half\n"));
|
||||
EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
|
||||
}
|
||||
}
|
||||
|
||||
EMAC_ENABLE_RX();
|
||||
EMAC_ENABLE_TX();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -259,20 +301,26 @@ unsigned int m_status;
|
|||
|
||||
void EMAC_RX_IRQHandler(void)
|
||||
{
|
||||
// NU_DEBUGF(("%s ... nu_eth_txrx_cb=0x%x\r\n", __FUNCTION__, nu_eth_txrx_cb));
|
||||
m_status = EMAC->INTSTS & 0xFFFF;
|
||||
EMAC->INTSTS = m_status;
|
||||
if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
|
||||
// Shouldn't goes here, unless descriptor corrupted
|
||||
NU_DEBUGF(("RX descriptor corrupted \r\n"));
|
||||
//return;
|
||||
mbed_error_printf("### RX Bus error [0x%x]\r\n", m_status);
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('B', nu_userData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
EMAC_DISABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('R', nu_userData);
|
||||
}
|
||||
if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('R', nu_userData);
|
||||
}
|
||||
|
||||
|
||||
void numaker_eth_trigger_rx(void)
|
||||
{
|
||||
EMAC_ENABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
|
||||
ETH_TRIGGER_RX();
|
||||
}
|
||||
|
||||
|
|
@ -281,16 +329,26 @@ int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
|
|||
unsigned int cur_entry, status;
|
||||
|
||||
cur_entry = EMAC->CRXDSA;
|
||||
if ((cur_entry == (uint32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) // cur_entry may equal to cur_rx_desc_ptr if RDU occures
|
||||
if ((cur_entry == (uint32_t)cur_rx_desc_ptr) && (!(m_status & EMAC_INTSTS_RDUIF_Msk))) { // cur_entry may equal to cur_rx_desc_ptr if RDU occures
|
||||
return -1;
|
||||
}
|
||||
status = cur_rx_desc_ptr->status1;
|
||||
|
||||
if(status & OWNERSHIP_EMAC)
|
||||
if (status & OWNERSHIP_EMAC) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (status & RXFD_RXGD) {
|
||||
*buf = cur_rx_desc_ptr->buf;
|
||||
*len = status & 0xFFFF;
|
||||
// length of payload should be <= 1514
|
||||
if (*len > (NU_ETH_MAX_FLEN - 4)) {
|
||||
NU_DEBUGF(("%s... unexpected long packet length=%d, buf=0x%x\r\n", __FUNCTION__, *len, *buf));
|
||||
*len = 0; // Skip this unexpected long packet
|
||||
}
|
||||
if (*len == (NU_ETH_MAX_FLEN - 4)) {
|
||||
NU_DEBUGF(("%s... length=%d, buf=0x%x\r\n", __FUNCTION__, *len, *buf));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -309,6 +367,10 @@ void EMAC_TX_IRQHandler(void)
|
|||
EMAC->INTSTS = status;
|
||||
if (status & EMAC_INTSTS_TXBEIF_Msk) {
|
||||
// Shouldn't goes here, unless descriptor corrupted
|
||||
mbed_error_printf("### TX Bus error [0x%x]\r\n", status);
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('B', nu_userData);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -319,16 +381,19 @@ void EMAC_TX_IRQHandler(void)
|
|||
fin_tx_desc_ptr = fin_tx_desc_ptr->next;
|
||||
}
|
||||
|
||||
if (nu_eth_txrx_cb != NULL) nu_eth_txrx_cb('T', nu_userData);
|
||||
if (nu_eth_txrx_cb != NULL) {
|
||||
nu_eth_txrx_cb('T', nu_userData);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *numaker_eth_get_tx_buf(void)
|
||||
{
|
||||
if(cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC)
|
||||
if (cur_tx_desc_ptr->status1 & OWNERSHIP_EMAC) {
|
||||
return (NULL);
|
||||
else
|
||||
} else {
|
||||
return (cur_tx_desc_ptr->buf);
|
||||
}
|
||||
}
|
||||
|
||||
void numaker_eth_trigger_tx(uint16_t length, void *p)
|
||||
{
|
||||
|
|
@ -346,8 +411,9 @@ int numaker_eth_link_ok(void)
|
|||
{
|
||||
/* first, a dummy read to latch */
|
||||
mdio_read(CONFIG_PHY_ADDR, MII_BMSR);
|
||||
if(mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS)
|
||||
if (mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & BMSR_LSTATUS) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -370,8 +436,7 @@ void mbed_mac_address(char *mac)
|
|||
// http://en.wikipedia.org/wiki/MAC_address
|
||||
uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800
|
||||
|
||||
if( word0 == 0xFFFFFFFF ) // Not burn any mac address at 1st 2 words of Data Flash
|
||||
{
|
||||
if (word0 == 0xFFFFFFFF) { // Not burn any mac address at 1st 2 words of Data Flash
|
||||
// with a semi-unique MAC address from the UUID
|
||||
/* Enable FMC ISP function */
|
||||
SYS_UnlockReg();
|
||||
|
|
@ -399,14 +464,16 @@ void mbed_mac_address(char *mac)
|
|||
NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]));
|
||||
}
|
||||
|
||||
void numaker_eth_enable_interrupts(void) {
|
||||
void numaker_eth_enable_interrupts(void)
|
||||
{
|
||||
EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
|
||||
EMAC_INTEN_TXIEN_Msk ;
|
||||
NVIC_EnableIRQ(EMAC_RX_IRQn);
|
||||
NVIC_EnableIRQ(EMAC_TX_IRQn);
|
||||
}
|
||||
|
||||
void numaker_eth_disable_interrupts(void) {
|
||||
void numaker_eth_disable_interrupts(void)
|
||||
{
|
||||
NVIC_DisableIRQ(EMAC_RX_IRQn);
|
||||
NVIC_DisableIRQ(EMAC_TX_IRQn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ extern "C" void numaker_eth_rx_next(void);
|
|||
/* \brief Flags for worker thread */
|
||||
#define FLAG_TX 1
|
||||
#define FLAG_RX 2
|
||||
#define FLAG_BUS_RESET 4
|
||||
|
||||
/** \brief Driver thread priority */
|
||||
#define THREAD_PRIORITY (osPriorityNormal)
|
||||
|
|
@ -82,6 +83,13 @@ void NUMAKER_EMAC::rx_isr()
|
|||
}
|
||||
}
|
||||
|
||||
void NUMAKER_EMAC::bus_isr()
|
||||
{
|
||||
if (thread) {
|
||||
osThreadFlagsSet(thread, FLAG_BUS_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
void NUMAKER_EMAC::tx_isr()
|
||||
{
|
||||
/* No-op at this stage */
|
||||
|
|
@ -90,14 +98,15 @@ void NUMAKER_EMAC::tx_isr()
|
|||
void NUMAKER_EMAC::ethernet_callback(char event, void *param)
|
||||
{
|
||||
NUMAKER_EMAC *enet = static_cast<NUMAKER_EMAC *>(param);
|
||||
switch (event)
|
||||
{
|
||||
switch (event) {
|
||||
case 'R': //For RX event
|
||||
enet->rx_isr();
|
||||
break;
|
||||
case 'T': //For TX event
|
||||
enet->tx_isr();
|
||||
break;
|
||||
case 'B': // For BUS event
|
||||
enet->bus_isr();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -172,11 +181,15 @@ void NUMAKER_EMAC::thread_function(void* pvParameters)
|
|||
static struct NUMAKER_EMAC *nu_enet = static_cast<NUMAKER_EMAC *>(pvParameters);
|
||||
|
||||
for (;;) {
|
||||
uint32_t flags = osThreadFlagsWait(FLAG_RX, osFlagsWaitAny, osWaitForever);
|
||||
uint32_t flags = osThreadFlagsWait(FLAG_RX | FLAG_BUS_RESET, osFlagsWaitAny, osWaitForever);
|
||||
|
||||
if (flags & FLAG_RX) {
|
||||
nu_enet->packet_rx();
|
||||
}
|
||||
if (flags & FLAG_BUS_RESET) {
|
||||
NU_DEBUGF(("BUS error and reset bus\r\n"));
|
||||
nu_enet->bus_reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +245,9 @@ bool NUMAKER_EMAC::link_out(emac_mem_buf_t *buf)
|
|||
TXLockMutex.lock();
|
||||
buffer = numaker_eth_get_tx_buf();
|
||||
NU_DEBUGF(("%s ... buffer=0x%x\r\n", __FUNCTION__, buffer));
|
||||
if( buffer == NULL ) goto error;
|
||||
if (buffer == NULL) {
|
||||
goto error;
|
||||
}
|
||||
/* copy frame from buf to driver buffers */
|
||||
for (q = buf; q != NULL; q = memory_manager->get_next(q)) {
|
||||
|
||||
|
|
@ -248,7 +263,9 @@ bool NUMAKER_EMAC::link_out(emac_mem_buf_t *buf)
|
|||
/* Point to next descriptor */
|
||||
numaker_eth_trigger_tx(PACKET_BUFFER_SIZE, NULL);
|
||||
buffer = numaker_eth_get_tx_buf();
|
||||
if( buffer == NULL ) goto error;
|
||||
if (buffer == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
byteslefttocopy = byteslefttocopy - (PACKET_BUFFER_SIZE - bufferoffset);
|
||||
payloadoffset = payloadoffset + (PACKET_BUFFER_SIZE - bufferoffset);
|
||||
|
|
@ -288,10 +305,14 @@ void NUMAKER_EMAC::phy_task()
|
|||
|
||||
if ((state & PHY_LINKED_STATE) && !(phy_state & PHY_LINKED_STATE)) {
|
||||
NU_DEBUGF(("Link Up\r\n"));
|
||||
if (emac_link_state_cb) emac_link_state_cb(true);
|
||||
if (emac_link_state_cb) {
|
||||
emac_link_state_cb(true);
|
||||
}
|
||||
} else if (!(state & PHY_LINKED_STATE) && (phy_state & PHY_LINKED_STATE)) {
|
||||
NU_DEBUGF(("Link Down\r\n"));
|
||||
if (emac_link_state_cb) emac_link_state_cb(false);
|
||||
if (emac_link_state_cb) {
|
||||
emac_link_state_cb(false);
|
||||
}
|
||||
}
|
||||
phy_state = state;
|
||||
|
||||
|
|
@ -300,11 +321,12 @@ void NUMAKER_EMAC::phy_task()
|
|||
bool NUMAKER_EMAC::power_up()
|
||||
{
|
||||
/* Initialize the hardware */
|
||||
if (!low_level_init_successful())
|
||||
if (!low_level_init_successful()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Worker thread */
|
||||
thread = create_new_thread("numaker_emac_thread", &NUMAKER_EMAC::thread_function, this, THREAD_STACKSIZE, THREAD_PRIORITY, &thread_cb);
|
||||
thread = create_new_thread("numaker_emac_thread", &NUMAKER_EMAC::thread_function, this, THREAD_STACKSIZE * 2, THREAD_PRIORITY, &thread_cb);
|
||||
|
||||
/* PHY monitoring task */
|
||||
phy_state = PHY_UNLINKED_STATE;
|
||||
|
|
@ -317,6 +339,16 @@ bool NUMAKER_EMAC::power_up()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NUMAKER_EMAC::bus_reset()
|
||||
{
|
||||
/* Initialize the hardware */
|
||||
if (!low_level_init_successful()) {
|
||||
return false;
|
||||
}
|
||||
numaker_eth_enable_interrupts();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
uint32_t NUMAKER_EMAC::get_mtu_size() const
|
||||
{
|
||||
|
|
@ -387,13 +419,15 @@ void NUMAKER_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
|
|||
}
|
||||
|
||||
|
||||
NUMAKER_EMAC &NUMAKER_EMAC::get_instance() {
|
||||
NUMAKER_EMAC &NUMAKER_EMAC::get_instance()
|
||||
{
|
||||
static NUMAKER_EMAC emac;
|
||||
return emac;
|
||||
}
|
||||
|
||||
// Weak so a module can override
|
||||
MBED_WEAK EMAC &EMAC::get_default_instance() {
|
||||
MBED_WEAK EMAC &EMAC::get_default_instance()
|
||||
{
|
||||
return NUMAKER_EMAC::get_instance();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -151,7 +151,9 @@ private:
|
|||
bool low_level_init_successful();
|
||||
void tx_isr();
|
||||
void rx_isr();
|
||||
void bus_isr();
|
||||
void packet_rx();
|
||||
bool bus_reset();
|
||||
int low_level_input(emac_mem_buf_t **buf);
|
||||
static void thread_function(void *pvParameters);
|
||||
void phy_task();
|
||||
|
|
|
|||
Loading…
Reference in New Issue