Merge pull request #12991 from OpenNuvoton/nuvoton_emac_bus_err

Nuvoton: Support EMAC bus reset as while bus err
pull/13069/head
Martin Kojtal 2020-06-04 15:21:40 +02:00 committed by GitHub
commit 096b3e80ec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 387 additions and 226 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 Nuvoton Technology Corp. * Copyright (c) 2018 Nuvoton Technology Corp.
* Copyright (c) 2018 ARM Limited * Copyright (c) 2018 ARM Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,24 +16,30 @@
* *
* Description: M480 MAC driver source file * Description: M480 MAC driver source file
*/ */
#include <stdbool.h>
#include "m480_eth.h" #include "m480_eth.h"
#include "mbed_toolchain.h" #include "mbed_toolchain.h"
//#define NU_TRACE
#include "numaker_eth_hal.h" #include "numaker_eth_hal.h"
#define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0) #define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0)
#define ETH_TRIGGER_TX() do{EMAC->TXST = 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_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_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 rx_desc[RX_DESCRIPTOR_NUM];
MBED_ALIGN(4) struct eth_descriptor tx_desc[TX_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; 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]; 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]; MBED_ALIGN(4) uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
eth_callback_t nu_eth_txrx_cb = NULL; eth_callback_t nu_eth_txrx_cb = NULL;
@ -41,6 +47,9 @@ void *nu_userData = NULL;
extern void ack_emac_rx_isr(void); 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 // PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
// Assume we want to set each tick to 100ns. // Assume we want to set each tick to 100ns.
// Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7 // Increase register = (100 * 2^31) / (10^9) = 214.71 =~ 215 = 0xD7
@ -65,7 +74,7 @@ static uint16_t mdio_read(uint8_t addr, uint8_t reg)
EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk; EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk); while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
return(EMAC->MIIMDAT); return (EMAC->MIIMDAT);
} }
static int reset_phy(void) static int reset_phy(void)
@ -78,16 +87,17 @@ static int reset_phy(void)
mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET); mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
delayCnt = 2000; delayCnt = 2000;
while(delayCnt > 0) { while (delayCnt > 0) {
delayCnt--; delayCnt--;
if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) if ((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) {
break; break;
}
} }
if(delayCnt == 0) { if (delayCnt == 0) {
NU_DEBUGF(("Reset phy failed\n")); NU_DEBUGF(("Reset phy failed\n"));
return(-1); return (-1);
} }
mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA | mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |
@ -100,27 +110,29 @@ static int reset_phy(void)
mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART); mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);
delayCnt = 200000; delayCnt = 200000;
while(delayCnt > 0) { while (delayCnt > 0) {
delayCnt--; delayCnt--;
if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) if ((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) {
break; break;
}
} }
if(delayCnt == 0) { if (delayCnt == 0) {
NU_DEBUGF(("AN failed. Set to 100 FULL\n")); NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
return(-1); return (-1);
} else { } else {
reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA); reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
phyLPAval = reg;
if(reg & ADVERTISE_100FULL) { if (reg & ADVERTISE_100FULL) {
NU_DEBUGF(("100 full\n")); NU_DEBUGF(("100 full\n"));
EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
} else if(reg & ADVERTISE_100HALF) { } else if (reg & ADVERTISE_100HALF) {
NU_DEBUGF(("100 half\n")); NU_DEBUGF(("100 half\n"));
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk; EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
} else if(reg & ADVERTISE_10FULL) { } else if (reg & ADVERTISE_10FULL) {
NU_DEBUGF(("10 full\n")); NU_DEBUGF(("10 full\n"));
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk; EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
} else { } else {
@ -128,10 +140,10 @@ static int reset_phy(void)
EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
} }
} }
printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1)); printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1));
printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2)); printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2));
return(0); return (0);
} }
@ -142,7 +154,7 @@ static void init_tx_desc(void)
cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0]; cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];
for(i = 0; i < TX_DESCRIPTOR_NUM; i++) { for (i = 0; i < TX_DESCRIPTOR_NUM; i++) {
tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN; tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN;
tx_desc[i].buf = &tx_buf[i][0]; tx_desc[i].buf = &tx_buf[i][0];
tx_desc[i].status2 = 0; tx_desc[i].status2 = 0;
@ -160,11 +172,11 @@ static void init_rx_desc(void)
cur_rx_desc_ptr = &rx_desc[0]; cur_rx_desc_ptr = &rx_desc[0];
for(i = 0; i < RX_DESCRIPTOR_NUM; i++) { for (i = 0; i < RX_DESCRIPTOR_NUM; i++) {
rx_desc[i].status1 = OWNERSHIP_EMAC; rx_desc[i].status1 = OWNERSHIP_EMAC;
rx_desc[i].buf = &rx_buf[i][0]; rx_desc[i].buf = &rx_buf[i][0];
rx_desc[i].status2 = 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]; EMAC->RXDSA = (unsigned int)&rx_desc[0];
return; return;
@ -191,13 +203,13 @@ static void __eth_clk_pin_init()
/* Enable IP clock */ /* Enable IP clock */
CLK_EnableModuleClock(EMAC_MODULE); CLK_EnableModuleClock(EMAC_MODULE);
// Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH // Configure MDC clock rate to HCLK / (127 + 1) = 1.25 MHz if system is running at 160 MH
CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127)); CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
/* Update System Core Clock */ /* Update System Core Clock */
SystemCoreClockUpdate(); SystemCoreClockUpdate();
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */ /* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
@ -211,10 +223,10 @@ static void __eth_clk_pin_init()
SYS->GPE_MFPH &= ~(SYS_GPE_MFPH_PE8MFP_Msk | SYS_GPE_MFPH_PE9MFP_Msk | SYS_GPE_MFPH_PE10MFP_Msk | SYS->GPE_MFPH &= ~(SYS_GPE_MFPH_PE8MFP_Msk | SYS_GPE_MFPH_PE9MFP_Msk | SYS_GPE_MFPH_PE10MFP_Msk |
SYS_GPE_MFPH_PE11MFP_Msk | SYS_GPE_MFPH_PE12MFP_Msk); SYS_GPE_MFPH_PE11MFP_Msk | SYS_GPE_MFPH_PE12MFP_Msk);
SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC | SYS->GPE_MFPH |= SYS_GPE_MFPH_PE8MFP_EMAC_RMII_MDC |
SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO | SYS_GPE_MFPH_PE9MFP_EMAC_RMII_MDIO |
SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 | SYS_GPE_MFPH_PE10MFP_EMAC_RMII_TXD0 |
SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 | SYS_GPE_MFPH_PE11MFP_EMAC_RMII_TXD1 |
SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN; SYS_GPE_MFPH_PE12MFP_EMAC_RMII_TXEN;
// Enable high slew rate on all RMII TX output pins // Enable high slew rate on all RMII TX output pins
PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) | PE->SLEWCTL = (GPIO_SLEWCTL_HIGH << GPIO_SLEWCTL_HSREN10_Pos) |
@ -230,13 +242,13 @@ static void __eth_clk_pin_init()
void numaker_eth_init(uint8_t *mac_addr) void numaker_eth_init(uint8_t *mac_addr)
{ {
// init CLK & pins // init CLK & pins
__eth_clk_pin_init(); __eth_clk_pin_init();
// Reset MAC // Reset MAC
EMAC->CTL = EMAC_CTL_RST_Msk; EMAC->CTL = EMAC_CTL_RST_Msk;
while(EMAC->CTL & EMAC_CTL_RST_Msk) {} while (EMAC->CTL & EMAC_CTL_RST_Msk) {}
init_tx_desc(); init_tx_desc();
init_rx_desc(); init_rx_desc();
@ -262,12 +274,33 @@ void numaker_eth_init(uint8_t *mac_addr)
EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk | EMAC->CAMCTL = EMAC_CAMCTL_CMPEN_Msk |
EMAC_CAMCTL_AMP_Msk | EMAC_CAMCTL_AMP_Msk |
EMAC_CAMCTL_ABP_Msk; EMAC_CAMCTL_ABP_Msk;
EMAC->CAMEN = 1; // Enable CAM entry 0 EMAC->CAMEN = 1; // Enable CAM entry 0
/* Limit the max receive frame length to 1514 + 4 */ /* Limit the max receive frame length to 1514 + 4 */
EMAC->MRFL = NU_ETH_MAX_FLEN; 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_RX();
EMAC_ENABLE_TX(); EMAC_ENABLE_TX();
@ -285,20 +318,26 @@ unsigned int m_status;
void EMAC_RX_IRQHandler(void) 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; m_status = EMAC->INTSTS & 0xFFFF;
EMAC->INTSTS = m_status; EMAC->INTSTS = m_status;
if (m_status & EMAC_INTSTS_RXBEIF_Msk) { if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
// Shouldn't goes here, unless descriptor corrupted // Shouldn't goes here, unless descriptor corrupted
NU_DEBUGF(("RX descriptor corrupted \r\n")); mbed_error_printf("### RX Bus error [0x%x]\r\n", m_status);
//return; 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) void numaker_eth_trigger_rx(void)
{ {
EMAC_ENABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
ETH_TRIGGER_RX(); ETH_TRIGGER_RX();
} }
@ -307,25 +346,35 @@ int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
unsigned int cur_entry, status; unsigned int cur_entry, status;
cur_entry = EMAC->CRXDSA; 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; return -1;
}
status = cur_rx_desc_ptr->status1; status = cur_rx_desc_ptr->status1;
if(status & OWNERSHIP_EMAC) if (status & OWNERSHIP_EMAC) {
return -1; return -1;
}
if (status & RXFD_RXGD) { if (status & RXFD_RXGD) {
*buf = cur_rx_desc_ptr->buf; *buf = cur_rx_desc_ptr->buf;
*len = status & 0xFFFF; *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; return 0;
} }
void numaker_eth_rx_next(void) void numaker_eth_rx_next(void)
{ {
cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC; cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
cur_rx_desc_ptr = cur_rx_desc_ptr->next; cur_rx_desc_ptr = cur_rx_desc_ptr->next;
} }
void EMAC_TX_IRQHandler(void) void EMAC_TX_IRQHandler(void)
{ {
@ -333,8 +382,12 @@ void EMAC_TX_IRQHandler(void)
status = EMAC->INTSTS & 0xFFFF0000; status = EMAC->INTSTS & 0xFFFF0000;
EMAC->INTSTS = status; EMAC->INTSTS = status;
if(status & EMAC_INTSTS_TXBEIF_Msk) { if (status & EMAC_INTSTS_TXBEIF_Msk) {
// Shouldn't goes here, unless descriptor corrupted // 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; return;
} }
@ -344,16 +397,19 @@ void EMAC_TX_IRQHandler(void)
fin_tx_desc_ptr = fin_tx_desc_ptr->next; 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) 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); return (NULL);
else } else {
return(cur_tx_desc_ptr->buf); return (cur_tx_desc_ptr->buf);
}
} }
void numaker_eth_trigger_tx(uint16_t length, void *p) void numaker_eth_trigger_tx(uint16_t length, void *p)
@ -370,11 +426,12 @@ void numaker_eth_trigger_tx(uint16_t length, void *p)
int numaker_eth_link_ok(void) int numaker_eth_link_ok(void)
{ {
/* first, a dummy read to latch */ /* first, a dummy read to latch */
mdio_read(CONFIG_PHY_ADDR, MII_BMSR); 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 1;
return 0; }
return 0;
} }
void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData) void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData)
@ -396,8 +453,7 @@ void mbed_mac_address(char *mac)
// http://en.wikipedia.org/wiki/MAC_address // http://en.wikipedia.org/wiki/MAC_address
uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800 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 // with a semi-unique MAC address from the UUID
/* Enable FMC ISP function */ /* Enable FMC ISP function */
SYS_UnlockReg(); SYS_UnlockReg();
@ -405,34 +461,36 @@ void mbed_mac_address(char *mac)
// = FMC_ReadUID(0); // = FMC_ReadUID(0);
uID1 = FMC_ReadUID(1); uID1 = FMC_ReadUID(1);
word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8; word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8;
word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF)<<12) | (FMC_ReadUID(2) & 0xFFF); word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF) << 12) | (FMC_ReadUID(2) & 0xFFF);
/* Disable FMC ISP function */ /* Disable FMC ISP function */
FMC_Close(); FMC_Close();
/* Lock protected registers */ /* Lock protected registers */
SYS_LockReg(); SYS_LockReg();
} }
word1 |= 0x00000200; word1 |= 0x00000200;
word1 &= 0x0000FEFF; word1 &= 0x0000FEFF;
mac[0] = (word1 & 0x0000ff00) >> 8; mac[0] = (word1 & 0x0000ff00) >> 8;
mac[1] = (word1 & 0x000000ff); mac[1] = (word1 & 0x000000ff);
mac[2] = (word0 & 0xff000000) >> 24; mac[2] = (word0 & 0xff000000) >> 24;
mac[3] = (word0 & 0x00ff0000) >> 16; mac[3] = (word0 & 0x00ff0000) >> 16;
mac[4] = (word0 & 0x0000ff00) >> 8; mac[4] = (word0 & 0x0000ff00) >> 8;
mac[5] = (word0 & 0x000000ff); mac[5] = (word0 & 0x000000ff);
NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5])); 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 |= EMAC_INTEN_RXIEN_Msk |
EMAC_INTEN_TXIEN_Msk ; EMAC_INTEN_TXIEN_Msk ;
NVIC_EnableIRQ(EMAC_RX_IRQn); NVIC_EnableIRQ(EMAC_RX_IRQn);
NVIC_EnableIRQ(EMAC_TX_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); NVIC_DisableIRQ(EMAC_RX_IRQn);
NVIC_DisableIRQ(EMAC_TX_IRQn);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 Nuvoton Technology Corp. * Copyright (c) 2018 Nuvoton Technology Corp.
* Copyright (c) 2018 ARM Limited * Copyright (c) 2018 ARM Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -16,30 +16,38 @@
* *
* Description: NUC472 MAC driver source file * Description: NUC472 MAC driver source file
*/ */
#include <stdbool.h>
#include "nuc472_eth.h" #include "nuc472_eth.h"
#include "mbed_toolchain.h" #include "mbed_toolchain.h"
//#define NU_TRACE
#include "numaker_eth_hal.h" #include "numaker_eth_hal.h"
#define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0) #define ETH_TRIGGER_RX() do{EMAC->RXST = 0;}while(0)
#define ETH_TRIGGER_TX() do{EMAC->TXST = 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_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_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 rx_desc[RX_DESCRIPTOR_NUM];
MBED_ALIGN(4) struct eth_descriptor tx_desc[TX_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; 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]; 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]; MBED_ALIGN(4) uint8_t tx_buf[TX_DESCRIPTOR_NUM][PACKET_BUFFER_SIZE];
eth_callback_t nu_eth_txrx_cb = NULL; eth_callback_t nu_eth_txrx_cb = NULL;
void *nu_userData = NULL; void *nu_userData = NULL;
extern void ack_emac_rx_isr(void); 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 // PTP source clock is 84MHz (Real chip using PLL). Each tick is 11.90ns
// Assume we want to set each tick to 100ns. // Assume we want to set each tick to 100ns.
@ -65,7 +73,7 @@ static uint16_t mdio_read(uint8_t addr, uint8_t reg)
EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk; EMAC->MIIMCTL = (addr << EMAC_MIIMCTL_PHYADDR_Pos) | reg | EMAC_MIIMCTL_BUSY_Msk | EMAC_MIIMCTL_MDCON_Msk;
while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk); while (EMAC->MIIMCTL & EMAC_MIIMCTL_BUSY_Msk);
return(EMAC->MIIMDAT); return (EMAC->MIIMDAT);
} }
static int reset_phy(void) static int reset_phy(void)
@ -78,16 +86,17 @@ static int reset_phy(void)
mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET); mdio_write(CONFIG_PHY_ADDR, MII_BMCR, BMCR_RESET);
delayCnt = 2000; delayCnt = 2000;
while(delayCnt > 0) { while (delayCnt > 0) {
delayCnt--; delayCnt--;
if((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) if ((mdio_read(CONFIG_PHY_ADDR, MII_BMCR) & BMCR_RESET) == 0) {
break; break;
}
} }
if(delayCnt == 0) { if (delayCnt == 0) {
NU_DEBUGF(("Reset phy failed\n")); NU_DEBUGF(("Reset phy failed\n"));
return(-1); return (-1);
} }
mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA | mdio_write(CONFIG_PHY_ADDR, MII_ADVERTISE, ADVERTISE_CSMA |
@ -100,27 +109,29 @@ static int reset_phy(void)
mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART); mdio_write(CONFIG_PHY_ADDR, MII_BMCR, reg | BMCR_ANRESTART);
delayCnt = 200000; delayCnt = 200000;
while(delayCnt > 0) { while (delayCnt > 0) {
delayCnt--; delayCnt--;
if((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) if ((mdio_read(CONFIG_PHY_ADDR, MII_BMSR) & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS))
== (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) {
break; break;
}
} }
if(delayCnt == 0) { if (delayCnt == 0) {
NU_DEBUGF(("AN failed. Set to 100 FULL\n")); NU_DEBUGF(("AN failed. Set to 100 FULL\n"));
EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
return(-1); return (-1);
} else { } else {
reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA); reg = mdio_read(CONFIG_PHY_ADDR, MII_LPA);
phyLPAval = reg;
if(reg & ADVERTISE_100FULL) { if (reg & ADVERTISE_100FULL) {
NU_DEBUGF(("100 full\n")); NU_DEBUGF(("100 full\n"));
EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); EMAC->CTL |= (EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
} else if(reg & ADVERTISE_100HALF) { } else if (reg & ADVERTISE_100HALF) {
NU_DEBUGF(("100 half\n")); NU_DEBUGF(("100 half\n"));
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk; EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_FUDUP_Msk) | EMAC_CTL_OPMODE_Msk;
} else if(reg & ADVERTISE_10FULL) { } else if (reg & ADVERTISE_10FULL) {
NU_DEBUGF(("10 full\n")); NU_DEBUGF(("10 full\n"));
EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk; EMAC->CTL = (EMAC->CTL & ~EMAC_CTL_OPMODE_Msk) | EMAC_CTL_FUDUP_Msk;
} else { } else {
@ -128,10 +139,10 @@ static int reset_phy(void)
EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk); EMAC->CTL &= ~(EMAC_CTL_OPMODE_Msk | EMAC_CTL_FUDUP_Msk);
} }
} }
printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1)); printf("PHY ID 1:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID1));
printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2)); printf("PHY ID 2:0x%x\r\n", mdio_read(CONFIG_PHY_ADDR, MII_PHYSID2));
return(0); return (0);
} }
@ -142,7 +153,7 @@ static void init_tx_desc(void)
cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0]; cur_tx_desc_ptr = fin_tx_desc_ptr = &tx_desc[0];
for(i = 0; i < TX_DESCRIPTOR_NUM; i++) { for (i = 0; i < TX_DESCRIPTOR_NUM; i++) {
tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN; tx_desc[i].status1 = TXFD_PADEN | TXFD_CRCAPP | TXFD_INTEN;
tx_desc[i].buf = &tx_buf[i][0]; tx_desc[i].buf = &tx_buf[i][0];
tx_desc[i].status2 = 0; tx_desc[i].status2 = 0;
@ -160,11 +171,11 @@ static void init_rx_desc(void)
cur_rx_desc_ptr = &rx_desc[0]; cur_rx_desc_ptr = &rx_desc[0];
for(i = 0; i < RX_DESCRIPTOR_NUM; i++) { for (i = 0; i < RX_DESCRIPTOR_NUM; i++) {
rx_desc[i].status1 = OWNERSHIP_EMAC; rx_desc[i].status1 = OWNERSHIP_EMAC;
rx_desc[i].buf = &rx_buf[i][0]; rx_desc[i].buf = &rx_buf[i][0];
rx_desc[i].status2 = 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]; EMAC->RXDSA = (unsigned int)&rx_desc[0];
return; return;
@ -188,24 +199,28 @@ void numaker_set_mac_addr(uint8_t *addr)
static void __eth_clk_pin_init() static void __eth_clk_pin_init()
{ {
/* Enable IP clock */ /* Unlock protected registers */
SYS_UnlockReg();
/* Enable IP clock */
CLK_EnableModuleClock(EMAC_MODULE); CLK_EnableModuleClock(EMAC_MODULE);
// Configure MDC clock rate to HCLK / (127 + 1) = 656 kHz if system is running at 84 MHz // 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)); CLK_SetModuleClock(EMAC_MODULE, 0, CLK_CLKDIV3_EMAC(127));
/* Update System Core Clock */
SystemCoreClockUpdate();
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
/* Init I/O Multi-function */ /* Init I/O Multi-function */
/*---------------------------------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------------------------------*/
// Configure RMII pins // Configure RMII pins
SYS->GPC_MFPL &= ~( SYS_GPC_MFPL_PC0MFP_Msk | SYS_GPC_MFPL_PC1MFP_Msk | SYS->GPC_MFPL &= ~(SYS_GPC_MFPL_PC0MFP_Msk | SYS_GPC_MFPL_PC1MFP_Msk |
SYS_GPC_MFPL_PC2MFP_Msk | SYS_GPC_MFPL_PC3MFP_Msk | SYS_GPC_MFPL_PC2MFP_Msk | SYS_GPC_MFPL_PC3MFP_Msk |
SYS_GPC_MFPL_PC4MFP_Msk | SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk ); SYS_GPC_MFPL_PC4MFP_Msk | SYS_GPC_MFPL_PC6MFP_Msk | SYS_GPC_MFPL_PC7MFP_Msk);
SYS->GPC_MFPL |= SYS_GPC_MFPL_PC0MFP_EMAC_REFCLK | SYS->GPC_MFPL |= SYS_GPC_MFPL_PC0MFP_EMAC_REFCLK |
SYS_GPC_MFPL_PC1MFP_EMAC_MII_RXERR | SYS_GPC_MFPL_PC1MFP_EMAC_MII_RXERR |
SYS_GPC_MFPL_PC2MFP_EMAC_MII_RXDV | SYS_GPC_MFPL_PC2MFP_EMAC_MII_RXDV |
SYS_GPC_MFPL_PC3MFP_EMAC_MII_RXD1 | SYS_GPC_MFPL_PC3MFP_EMAC_MII_RXD1 |
SYS_GPC_MFPL_PC4MFP_EMAC_MII_RXD0 | SYS_GPC_MFPL_PC4MFP_EMAC_MII_RXD0 |
SYS_GPC_MFPL_PC6MFP_EMAC_MII_TXD0 | SYS_GPC_MFPL_PC6MFP_EMAC_MII_TXD0 |
SYS_GPC_MFPL_PC7MFP_EMAC_MII_TXD1; SYS_GPC_MFPL_PC7MFP_EMAC_MII_TXD1;
SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk; SYS->GPC_MFPH &= ~SYS_GPC_MFPH_PC8MFP_Msk;
SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_MII_TXEN; SYS->GPC_MFPH |= SYS_GPC_MFPH_PC8MFP_EMAC_MII_TXEN;
@ -216,24 +231,24 @@ 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_Msk | SYS_GPB_MFPH_PB15MFP_Msk);
SYS->GPB_MFPH |= SYS_GPB_MFPH_PB14MFP_EMAC_MII_MDC | SYS_GPB_MFPH_PB15MFP_EMAC_MII_MDIO; 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) void numaker_eth_init(uint8_t *mac_addr)
{ {
// init CLK & pins // init CLK & pins
__eth_clk_pin_init(); __eth_clk_pin_init();
// Reset MAC // Reset MAC
EMAC->CTL = EMAC_CTL_RST_Msk; EMAC->CTL = EMAC_CTL_RST_Msk;
while (EMAC->CTL & EMAC_CTL_RST_Msk) {}
init_tx_desc(); init_tx_desc();
init_rx_desc(); init_rx_desc();
numaker_set_mac_addr(mac_addr); // need to reconfigure hardware address 'cos we just RESET emc... 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->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 | EMAC->INTEN |= EMAC_INTEN_RXIEN_Msk |
@ -244,7 +259,34 @@ void numaker_eth_init(uint8_t *mac_addr)
EMAC_INTEN_TXABTIEN_Msk | EMAC_INTEN_TXABTIEN_Msk |
EMAC_INTEN_TXCPIEN_Msk | EMAC_INTEN_TXCPIEN_Msk |
EMAC_INTEN_TXBEIEN_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) 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; m_status = EMAC->INTSTS & 0xFFFF;
EMAC->INTSTS = m_status; EMAC->INTSTS = m_status;
if (m_status & EMAC_INTSTS_RXBEIF_Msk) { if (m_status & EMAC_INTSTS_RXBEIF_Msk) {
// Shouldn't goes here, unless descriptor corrupted // Shouldn't goes here, unless descriptor corrupted
NU_DEBUGF(("RX descriptor corrupted \r\n")); mbed_error_printf("### RX Bus error [0x%x]\r\n", m_status);
//return; 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) void numaker_eth_trigger_rx(void)
{ {
EMAC_ENABLE_INT(EMAC, (EMAC_INTEN_RDUIEN_Msk | EMAC_INTEN_RXGDIEN_Msk));
ETH_TRIGGER_RX(); ETH_TRIGGER_RX();
} }
@ -281,25 +329,35 @@ int numaker_eth_get_rx_buf(uint16_t *len, uint8_t **buf)
unsigned int cur_entry, status; unsigned int cur_entry, status;
cur_entry = EMAC->CRXDSA; 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; return -1;
}
status = cur_rx_desc_ptr->status1; status = cur_rx_desc_ptr->status1;
if(status & OWNERSHIP_EMAC) if (status & OWNERSHIP_EMAC) {
return -1; return -1;
}
if (status & RXFD_RXGD) { if (status & RXFD_RXGD) {
*buf = cur_rx_desc_ptr->buf; *buf = cur_rx_desc_ptr->buf;
*len = status & 0xFFFF; *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; return 0;
} }
void numaker_eth_rx_next(void) void numaker_eth_rx_next(void)
{ {
cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC; cur_rx_desc_ptr->status1 = OWNERSHIP_EMAC;
cur_rx_desc_ptr = cur_rx_desc_ptr->next; cur_rx_desc_ptr = cur_rx_desc_ptr->next;
} }
void EMAC_TX_IRQHandler(void) void EMAC_TX_IRQHandler(void)
{ {
@ -307,8 +365,12 @@ void EMAC_TX_IRQHandler(void)
status = EMAC->INTSTS & 0xFFFF0000; status = EMAC->INTSTS & 0xFFFF0000;
EMAC->INTSTS = status; EMAC->INTSTS = status;
if(status & EMAC_INTSTS_TXBEIF_Msk) { if (status & EMAC_INTSTS_TXBEIF_Msk) {
// Shouldn't goes here, unless descriptor corrupted // 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; return;
} }
@ -318,16 +380,19 @@ void EMAC_TX_IRQHandler(void)
fin_tx_desc_ptr = fin_tx_desc_ptr->next; 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) 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); return (NULL);
else } else {
return(cur_tx_desc_ptr->buf); return (cur_tx_desc_ptr->buf);
}
} }
void numaker_eth_trigger_tx(uint16_t length, void *p) void numaker_eth_trigger_tx(uint16_t length, void *p)
@ -344,11 +409,12 @@ void numaker_eth_trigger_tx(uint16_t length, void *p)
int numaker_eth_link_ok(void) int numaker_eth_link_ok(void)
{ {
/* first, a dummy read to latch */ /* first, a dummy read to latch */
mdio_read(CONFIG_PHY_ADDR, MII_BMSR); 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 1;
return 0; }
return 0;
} }
void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData) void numaker_eth_set_cb(eth_callback_t eth_cb, void *userData)
@ -370,8 +436,7 @@ void mbed_mac_address(char *mac)
// http://en.wikipedia.org/wiki/MAC_address // http://en.wikipedia.org/wiki/MAC_address
uint32_t word1 = *(uint32_t *)0x7F800; // 2KB Data Flash at 0x7F800 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 // with a semi-unique MAC address from the UUID
/* Enable FMC ISP function */ /* Enable FMC ISP function */
SYS_UnlockReg(); SYS_UnlockReg();
@ -379,34 +444,36 @@ void mbed_mac_address(char *mac)
// = FMC_ReadUID(0); // = FMC_ReadUID(0);
uID1 = FMC_ReadUID(1); uID1 = FMC_ReadUID(1);
word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8; word1 = (uID1 & 0x003FFFFF) | ((uID1 & 0x030000) << 6) >> 8;
word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF)<<12) | (FMC_ReadUID(2) & 0xFFF); word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uID1 & 0xFF) << 12) | (FMC_ReadUID(2) & 0xFFF);
/* Disable FMC ISP function */ /* Disable FMC ISP function */
FMC_Close(); FMC_Close();
/* Lock protected registers */ /* Lock protected registers */
SYS_LockReg(); SYS_LockReg();
} }
word1 |= 0x00000200; word1 |= 0x00000200;
word1 &= 0x0000FEFF; word1 &= 0x0000FEFF;
mac[0] = (word1 & 0x0000ff00) >> 8; mac[0] = (word1 & 0x0000ff00) >> 8;
mac[1] = (word1 & 0x000000ff); mac[1] = (word1 & 0x000000ff);
mac[2] = (word0 & 0xff000000) >> 24; mac[2] = (word0 & 0xff000000) >> 24;
mac[3] = (word0 & 0x00ff0000) >> 16; mac[3] = (word0 & 0x00ff0000) >> 16;
mac[4] = (word0 & 0x0000ff00) >> 8; mac[4] = (word0 & 0x0000ff00) >> 8;
mac[5] = (word0 & 0x000000ff); mac[5] = (word0 & 0x000000ff);
NU_DEBUGF(("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", mac[0], mac[1],mac[2],mac[3],mac[4],mac[5])); 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 |= EMAC_INTEN_RXIEN_Msk |
EMAC_INTEN_TXIEN_Msk ; EMAC_INTEN_TXIEN_Msk ;
NVIC_EnableIRQ(EMAC_RX_IRQn); NVIC_EnableIRQ(EMAC_RX_IRQn);
NVIC_EnableIRQ(EMAC_TX_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); NVIC_DisableIRQ(EMAC_RX_IRQn);
NVIC_DisableIRQ(EMAC_TX_IRQn);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2018 Nuvoton Technology Corp. * Copyright (c) 2018 Nuvoton Technology Corp.
* Copyright (c) 2018 ARM Limited * Copyright (c) 2018 ARM Limited
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -37,7 +37,7 @@
#include "numaker_eth_hal.h" #include "numaker_eth_hal.h"
/******************************************************************************** /********************************************************************************
* *
********************************************************************************/ ********************************************************************************/
#define NU_BUFF_ALIGNMENT 4 #define NU_BUFF_ALIGNMENT 4
#define PHY_LINKED_STATE 1 #define PHY_LINKED_STATE 1
@ -48,6 +48,7 @@ extern "C" void numaker_eth_rx_next(void);
/* \brief Flags for worker thread */ /* \brief Flags for worker thread */
#define FLAG_TX 1 #define FLAG_TX 1
#define FLAG_RX 2 #define FLAG_RX 2
#define FLAG_BUS_RESET 4
/** \brief Driver thread priority */ /** \brief Driver thread priority */
#define THREAD_PRIORITY (osPriorityNormal) #define THREAD_PRIORITY (osPriorityNormal)
@ -82,24 +83,32 @@ void NUMAKER_EMAC::rx_isr()
} }
} }
void NUMAKER_EMAC::bus_isr()
{
if (thread) {
osThreadFlagsSet(thread, FLAG_BUS_RESET);
}
}
void NUMAKER_EMAC::tx_isr() void NUMAKER_EMAC::tx_isr()
{ {
/* No-op at this stage */ /* No-op at this stage */
} }
void NUMAKER_EMAC::ethernet_callback(char event, void *param) void NUMAKER_EMAC::ethernet_callback(char event, void *param)
{ {
NUMAKER_EMAC *enet = static_cast<NUMAKER_EMAC *>(param); NUMAKER_EMAC *enet = static_cast<NUMAKER_EMAC *>(param);
switch (event) switch (event) {
{ case 'R': //For RX event
case 'R': //For RX event enet->rx_isr();
enet->rx_isr(); break;
break; case 'T': //For TX event
case 'T': //For TX event enet->tx_isr();
enet->tx_isr(); break;
break; case 'B': // For BUS event
default: enet->bus_isr();
break; default:
break;
} }
} }
@ -112,13 +121,13 @@ bool NUMAKER_EMAC::low_level_init_successful()
/* Init ETH */ /* Init ETH */
mbed_mac_address((char *)hwaddr); mbed_mac_address((char *)hwaddr);
printf("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", hwaddr[0], hwaddr[1],hwaddr[2],hwaddr[3],hwaddr[4],hwaddr[5]); printf("mac address %02x-%02x-%02x-%02x-%02x-%02x \r\n", hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
/* Enable clock & set EMAC configuration */ /* Enable clock & set EMAC configuration */
/* Enable MAC and DMA transmission and reception */ /* Enable MAC and DMA transmission and reception */
numaker_eth_init(hwaddr); numaker_eth_init(hwaddr);
numaker_eth_set_cb(&NUMAKER_EMAC::ethernet_callback, this); numaker_eth_set_cb(&NUMAKER_EMAC::ethernet_callback, this);
return true; return true;
} }
@ -133,7 +142,7 @@ int NUMAKER_EMAC::low_level_input(emac_mem_buf_t **buf)
uint32_t payloadoffset = 0; uint32_t payloadoffset = 0;
/* get received frame */ /* get received frame */
if ( numaker_eth_get_rx_buf(&len, &buffer) != 0) { if (numaker_eth_get_rx_buf(&len, &buffer) != 0) {
return -1; return -1;
} }
byteslefttocopy = len; byteslefttocopy = len;
@ -148,10 +157,10 @@ int NUMAKER_EMAC::low_level_input(emac_mem_buf_t **buf)
for (q = *buf; q != NULL; q = memory_manager->get_next(q)) { for (q = *buf; q != NULL; q = memory_manager->get_next(q)) {
byteslefttocopy = memory_manager->get_len(q); byteslefttocopy = memory_manager->get_len(q);
payloadoffset = 0; payloadoffset = 0;
NU_DEBUGF(("offset=[%d], bytes-to-copy[%d]\r\n",bufferoffset,byteslefttocopy)); NU_DEBUGF(("offset=[%d], bytes-to-copy[%d]\r\n", bufferoffset, byteslefttocopy));
/* Copy data in pbuf */ /* Copy data in pbuf */
memcpy(static_cast<uint8_t *>(memory_manager->get_ptr(q)) + payloadoffset, static_cast<uint8_t *>(buffer) + bufferoffset, byteslefttocopy); memcpy(static_cast<uint8_t *>(memory_manager->get_ptr(q)) + payloadoffset, static_cast<uint8_t *>(buffer) + bufferoffset, byteslefttocopy);
bufferoffset = bufferoffset + byteslefttocopy; bufferoffset = bufferoffset + byteslefttocopy;
} }
} }
@ -167,16 +176,20 @@ int NUMAKER_EMAC::low_level_input(emac_mem_buf_t **buf)
* \param[in] pvParameters pointer to the interface data * \param[in] pvParameters pointer to the interface data
*/ */
void NUMAKER_EMAC::thread_function(void* pvParameters) void NUMAKER_EMAC::thread_function(void *pvParameters)
{ {
static struct NUMAKER_EMAC *nu_enet = static_cast<NUMAKER_EMAC *>(pvParameters); static struct NUMAKER_EMAC *nu_enet = static_cast<NUMAKER_EMAC *>(pvParameters);
for (;;) { for (;;) {
uint32_t flags = osThreadFlagsWait(FLAG_RX, osFlagsWaitAny, osWaitForever); uint32_t flags = osThreadFlagsWait(FLAG_RX | FLAG_BUS_RESET, osFlagsWaitAny, osWaitForever);
if (flags & FLAG_RX) { if (flags & FLAG_RX) {
nu_enet->packet_rx(); nu_enet->packet_rx();
} }
if (flags & FLAG_BUS_RESET) {
NU_DEBUGF(("BUS error and reset bus\r\n"));
nu_enet->bus_reset();
}
} }
} }
@ -187,20 +200,20 @@ void NUMAKER_EMAC::thread_function(void* pvParameters)
*/ */
void NUMAKER_EMAC::packet_rx() void NUMAKER_EMAC::packet_rx()
{ {
/* move received packet into a new buf */ /* move received packet into a new buf */
while (1) { while (1) {
emac_mem_buf_t *p = NULL; emac_mem_buf_t *p = NULL;
if (low_level_input(&p) < 0) { if (low_level_input(&p) < 0) {
break; break;
} }
if (p) { if (p) {
NU_DEBUGF(("%s ... p=0x%x\r\n",__FUNCTION__,p)); NU_DEBUGF(("%s ... p=0x%x\r\n", __FUNCTION__, p));
emac_link_input_cb(p); emac_link_input_cb(p);
} }
numaker_eth_rx_next(); numaker_eth_rx_next();
} }
numaker_eth_trigger_rx(); numaker_eth_trigger_rx();
} }
@ -231,15 +244,17 @@ bool NUMAKER_EMAC::link_out(emac_mem_buf_t *buf)
/* Get exclusive access */ /* Get exclusive access */
TXLockMutex.lock(); TXLockMutex.lock();
buffer = numaker_eth_get_tx_buf(); buffer = numaker_eth_get_tx_buf();
NU_DEBUGF(("%s ... buffer=0x%x\r\n",__FUNCTION__, buffer)); 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 */ /* copy frame from buf to driver buffers */
for (q = buf; q != NULL; q = memory_manager->get_next(q)) { for (q = buf; q != NULL; q = memory_manager->get_next(q)) {
/* Get bytes in current lwIP buffer */ /* Get bytes in current lwIP buffer */
byteslefttocopy = memory_manager->get_len(q); byteslefttocopy = memory_manager->get_len(q);
payloadoffset = 0; payloadoffset = 0;
NU_DEBUGF(("offset=%d, bytes-to-copy=%d\r\n",bufferoffset, byteslefttocopy)); NU_DEBUGF(("offset=%d, bytes-to-copy=%d\r\n", bufferoffset, byteslefttocopy));
/* Check if the length of data to copy is bigger than Tx buffer size*/ /* Check if the length of data to copy is bigger than Tx buffer size*/
while ((byteslefttocopy + bufferoffset) > PACKET_BUFFER_SIZE) { while ((byteslefttocopy + bufferoffset) > PACKET_BUFFER_SIZE) {
/* Copy data to Tx buffer*/ /* Copy data to Tx buffer*/
@ -248,20 +263,22 @@ bool NUMAKER_EMAC::link_out(emac_mem_buf_t *buf)
/* Point to next descriptor */ /* Point to next descriptor */
numaker_eth_trigger_tx(PACKET_BUFFER_SIZE, NULL); numaker_eth_trigger_tx(PACKET_BUFFER_SIZE, NULL);
buffer = numaker_eth_get_tx_buf(); buffer = numaker_eth_get_tx_buf();
if( buffer == NULL ) goto error; if (buffer == NULL) {
goto error;
}
byteslefttocopy = byteslefttocopy - (PACKET_BUFFER_SIZE - bufferoffset); byteslefttocopy = byteslefttocopy - (PACKET_BUFFER_SIZE - bufferoffset);
payloadoffset = payloadoffset + (PACKET_BUFFER_SIZE - bufferoffset); payloadoffset = payloadoffset + (PACKET_BUFFER_SIZE - bufferoffset);
framelength = framelength + (PACKET_BUFFER_SIZE - bufferoffset); framelength = framelength + (PACKET_BUFFER_SIZE - bufferoffset);
bufferoffset = 0; bufferoffset = 0;
} }
/* Copy the remaining bytes */ /* Copy the remaining bytes */
memcpy(static_cast<uint8_t *>(buffer) + bufferoffset, static_cast<uint8_t *>(memory_manager->get_ptr(q)) + payloadoffset, byteslefttocopy); memcpy(static_cast<uint8_t *>(buffer) + bufferoffset, static_cast<uint8_t *>(memory_manager->get_ptr(q)) + payloadoffset, byteslefttocopy);
bufferoffset = bufferoffset + byteslefttocopy; bufferoffset = bufferoffset + byteslefttocopy;
framelength = framelength + byteslefttocopy; framelength = framelength + byteslefttocopy;
} }
/* Prepare transmit descriptors to give to DMA */ /* Prepare transmit descriptors to give to DMA */
numaker_eth_trigger_tx(framelength, NULL); numaker_eth_trigger_tx(framelength, NULL);
@ -280,57 +297,72 @@ error:
void NUMAKER_EMAC::phy_task() void NUMAKER_EMAC::phy_task()
{ {
// Get current status // Get current status
int state; int state;
state = numaker_eth_link_ok(); state = numaker_eth_link_ok();
if ((state & PHY_LINKED_STATE) && !(phy_state & PHY_LINKED_STATE)) { if ((state & PHY_LINKED_STATE) && !(phy_state & PHY_LINKED_STATE)) {
NU_DEBUGF(("Link Up\r\n")); 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)) { } else if (!(state & PHY_LINKED_STATE) && (phy_state & PHY_LINKED_STATE)) {
NU_DEBUGF(("Link Down\r\n")); 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; phy_state = state;
} }
bool NUMAKER_EMAC::power_up() bool NUMAKER_EMAC::power_up()
{ {
/* Initialize the hardware */ /* Initialize the hardware */
if (!low_level_init_successful()) if (!low_level_init_successful()) {
return false; return false;
}
/* Worker thread */ /* 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 monitoring task */
phy_state = PHY_UNLINKED_STATE; phy_state = PHY_UNLINKED_STATE;
phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &NUMAKER_EMAC::phy_task)); phy_task_handle = mbed::mbed_event_queue()->call_every(PHY_TASK_PERIOD_MS, mbed::callback(this, &NUMAKER_EMAC::phy_task));
/* Allow the PHY task to detect the initial link state and set up the proper flags */ /* Allow the PHY task to detect the initial link state and set up the proper flags */
osDelay(10); osDelay(10);
numaker_eth_enable_interrupts(); numaker_eth_enable_interrupts();
return true; 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 uint32_t NUMAKER_EMAC::get_mtu_size() const
{ {
return NU_ETH_MTU_SIZE; return NU_ETH_MTU_SIZE;
} }
uint32_t NUMAKER_EMAC::get_align_preference() const uint32_t NUMAKER_EMAC::get_align_preference() const
{ {
return NU_BUFF_ALIGNMENT; return NU_BUFF_ALIGNMENT;
} }
void NUMAKER_EMAC::get_ifname(char *name, uint8_t size) const void NUMAKER_EMAC::get_ifname(char *name, uint8_t size) const
{ {
memcpy(name, NU_ETH_IF_NAME, (size < sizeof(NU_ETH_IF_NAME)) ? size : sizeof(NU_ETH_IF_NAME)); memcpy(name, NU_ETH_IF_NAME, (size < sizeof(NU_ETH_IF_NAME)) ? size : sizeof(NU_ETH_IF_NAME));
} }
uint8_t NUMAKER_EMAC::get_hwaddr_size() const uint8_t NUMAKER_EMAC::get_hwaddr_size() const
@ -346,39 +378,39 @@ bool NUMAKER_EMAC::get_hwaddr(uint8_t *addr) const
void NUMAKER_EMAC::set_hwaddr(const uint8_t *addr) void NUMAKER_EMAC::set_hwaddr(const uint8_t *addr)
{ {
memcpy(hwaddr, addr, sizeof hwaddr); memcpy(hwaddr, addr, sizeof hwaddr);
numaker_set_mac_addr(const_cast<uint8_t*>(addr)); numaker_set_mac_addr(const_cast<uint8_t *>(addr));
} }
void NUMAKER_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb) void NUMAKER_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb)
{ {
emac_link_input_cb = input_cb; emac_link_input_cb = input_cb;
} }
void NUMAKER_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb) void NUMAKER_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
{ {
emac_link_state_cb = state_cb; emac_link_state_cb = state_cb;
} }
void NUMAKER_EMAC::add_multicast_group(const uint8_t *addr) void NUMAKER_EMAC::add_multicast_group(const uint8_t *addr)
{ {
/* No-op at this stage */ /* No-op at this stage */
} }
void NUMAKER_EMAC::remove_multicast_group(const uint8_t *addr) void NUMAKER_EMAC::remove_multicast_group(const uint8_t *addr)
{ {
/* No-op at this stage */ /* No-op at this stage */
} }
void NUMAKER_EMAC::set_all_multicast(bool all) void NUMAKER_EMAC::set_all_multicast(bool all)
{ {
/* No-op at this stage */ /* No-op at this stage */
} }
void NUMAKER_EMAC::power_down() void NUMAKER_EMAC::power_down()
{ {
/* No-op at this stage */ /* No-op at this stage */
} }
void NUMAKER_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr) void NUMAKER_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
@ -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; static NUMAKER_EMAC emac;
return emac; return emac;
} }
// Weak so a module can override // 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(); return NUMAKER_EMAC::get_instance();
} }

View File

@ -151,9 +151,11 @@ private:
bool low_level_init_successful(); bool low_level_init_successful();
void tx_isr(); void tx_isr();
void rx_isr(); void rx_isr();
void bus_isr();
void packet_rx(); void packet_rx();
bool bus_reset();
int low_level_input(emac_mem_buf_t **buf); int low_level_input(emac_mem_buf_t **buf);
static void thread_function(void* pvParameters); static void thread_function(void *pvParameters);
void phy_task(); void phy_task();
static void ethernet_callback(char event, void *param); static void ethernet_callback(char event, void *param);