ethernet: fix some bugs in phy&mac driver

1. Original register mapping for LAN8720 has some registers that doesn't exist/support.
So just remove them, and fix the power and init function for LAN8720.
2. GPIO16 and GPIO17 is occupied by PSRAM, so only ETH_CLOCK_GPIO_IN mode is supported in that case if using PSRAM.
3. Fix bug of OTA failing with Ethernet
4. Fix bug of multicast with Ethernet
5. Fix potential memory leak
This commit is contained in:
morris 2018-10-15 20:35:05 +08:00
parent 8725bce5bc
commit cb98f5a814
8 changed files with 202 additions and 199 deletions

View file

@ -56,7 +56,7 @@ void esp_spiram_init_cache();
/**
* @brief Memory test for SPI RAM. Should be called after SPI RAM is initialized and
* (in case of a dual-core system) the app CPU is online. This test overwrites the
* (in case of a dual-core system) the app CPU is online. This test overwrites the
* memory with crap, so do not call after e.g. the heap allocator has stored important
* stuff in SPI RAM.
*
@ -102,4 +102,14 @@ void esp_spiram_writeback_cache();
esp_err_t esp_spiram_reserve_dma_pool(size_t size);
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return
* - true SPI RAM has been initialized successfully
* - false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized(void);
#endif

View file

@ -1,5 +1,5 @@
/*
Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
Abstraction layer for spi-ram. For now, it's no more than a stub for the spiram_psram functions, but if
we add more types of external RAM memory, this can be made into a more intelligent dispatcher.
*/
@ -159,7 +159,7 @@ esp_err_t esp_spiram_init()
}
#endif
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
ESP_EARLY_LOGI(TAG, "Found %dMBit SPI RAM device",
(esp_spiram_get_size()*8)/(1024*1024));
ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_F40M_S40M ? "flash 40m sram 40m" : \
PSRAM_SPEED == PSRAM_CACHE_F80M_S40M ? "flash 80m sram 40m" : \
@ -225,7 +225,7 @@ size_t esp_spiram_get_size()
Note that this routine assumes some unique mapping for the first 2 banks of the PSRAM memory range, as well as the
2 banks after the 2 MiB mark.
*/
void IRAM_ATTR esp_spiram_writeback_cache()
void IRAM_ATTR esp_spiram_writeback_cache()
{
int x;
volatile int i=0;
@ -234,7 +234,7 @@ void IRAM_ATTR esp_spiram_writeback_cache()
if (!spiram_inited) return;
//We need cache enabled for this to work. Re-enable it if needed; make sure we
//We need cache enabled for this to work. Re-enable it if needed; make sure we
//disable it again on exit as well.
if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<0);
@ -257,10 +257,10 @@ void IRAM_ATTR esp_spiram_writeback_cache()
}
#else
/*
Low/high psram cache mode uses one 32K cache for the lowest 2MiB of SPI flash and another 32K for the highest
Low/high psram cache mode uses one 32KB cache for the lowest 2MiB of SPI flash and another 32K for the highest
2MiB. Clear this by reading from both regions.
Note: this assumes the amount of external RAM is >2M. If it is 2M or less, what this code does is undefined. If
we ever support external RAM chips of 2M or smaller, this may need adjusting.
Note: this assumes the amount of external RAM is >2MB. If it is 2MB or less, what this code does is undefined. If
we ever support external RAM chips of 2MB or smaller, this may need adjusting.
*/
for (x=0; x<1024*64; x+=32) {
i+=psram[x];
@ -280,4 +280,15 @@ void IRAM_ATTR esp_spiram_writeback_cache()
#endif
}
/**
* @brief If SPI RAM(PSRAM) has been initialized
*
* @return true SPI RAM has been initialized successfully
* @return false SPI RAM hasn't been initialized or initialized failed
*/
bool esp_spiram_is_initialized()
{
return spiram_inited;
}
#endif

View file

@ -14,8 +14,7 @@
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "rom/ets_sys.h"
#include "rom/gpio.h"
@ -98,4 +97,5 @@ void emac_mac_init(void)
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACDUPLEX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACMII);
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED);
REG_SET_BIT(EMAC_GMACFF_REG, EMAC_PAM);
}

View file

@ -39,6 +39,7 @@
#include "esp_eth.h"
#include "esp_intr_alloc.h"
#include "esp_pm.h"
#include "esp_spiram.h"
#include "driver/periph_ctrl.h"
@ -59,8 +60,8 @@
static struct emac_config_data emac_config;
static dma_extended_desc_t *emac_dma_rx_chain_buf[DMA_RX_BUF_NUM];
static dma_extended_desc_t *emac_dma_tx_chain_buf[DMA_TX_BUF_NUM];
static dma_extended_desc_t *emac_dma_rx_chain_buf;
static dma_extended_desc_t *emac_dma_tx_chain_buf;
static uint8_t *emac_dma_rx_buf[DMA_RX_BUF_NUM];
static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM];
@ -72,6 +73,7 @@ static uint8_t emac_sig_cnt[EMAC_SIG_MAX] = {0};
static TimerHandle_t emac_timer = NULL;
static SemaphoreHandle_t emac_rx_xMutex = NULL;
static SemaphoreHandle_t emac_tx_xMutex = NULL;
static intr_handle_t eth_intr_handle = NULL;
static const char *TAG = "emac";
static bool pause_send = false;
#ifdef CONFIG_PM_ENABLE
@ -93,7 +95,7 @@ void esp_eth_get_mac(uint8_t mac[6])
esp_err_t esp_eth_set_mac(const uint8_t mac[6])
{
if ((mac[0] & 0x01) == 0) {
if (!(mac[0] & 0x01)) {
memcpy(&(emac_config.macaddr[0]), mac, 6);
return ESP_OK;
} else {
@ -106,22 +108,20 @@ eth_speed_mode_t esp_eth_get_speed(void)
return emac_config.emac_phy_get_speed_mode();
}
static void emac_setup_tx_desc(struct dma_extended_desc *tx_desc, uint32_t size)
static void emac_setup_tx_desc(dma_extended_desc_t *tx_desc, uint32_t size)
{
tx_desc->basic.desc1 = size & 0xfff;
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL |
EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT |
EMAC_DESC_SECOND_ADDR_CHAIN;
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT |
EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
}
static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc)
static void emac_clean_tx_desc(dma_extended_desc_t *tx_desc)
{
tx_desc->basic.desc1 = 0;
tx_desc->basic.desc0 = 0;
}
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc,
uint32_t buf_ptr)
static void emac_clean_rx_desc(dma_extended_desc_t *rx_desc, uint32_t buf_ptr)
{
if (buf_ptr != 0) {
rx_desc->basic.desc2 = buf_ptr;
@ -184,46 +184,46 @@ static void emac_reset_dma_chain(void)
static void emac_init_dma_chain(void)
{
int i;
uint32_t dma_phy;
dma_extended_desc_t *p = NULL;
//init tx chain
emac_config.dma_etx = emac_dma_tx_chain_buf[0];
emac_config.dma_etx = emac_dma_tx_chain_buf;
emac_config.cnt_tx = 0;
emac_config.cur_tx = 0;
emac_config.dirty_tx = 0;
p = emac_dma_tx_chain_buf[0];
dma_phy = (uint32_t)(emac_config.dma_etx);
p = emac_config.dma_etx;
for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++) {
dma_phy += sizeof(dma_extended_desc_t);
emac_clean_tx_desc(p);
/* point to the buffer */
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
/* point to next descriptor */
p->basic.desc3 = (uint32_t)(emac_dma_tx_chain_buf[i + 1]);
p = emac_dma_tx_chain_buf[i + 1];
p->basic.desc3 = dma_phy;
p++;
}
emac_clean_tx_desc(p);
/* point to the buffer */
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
/* point to first descriptor */
p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
//init rx chain
emac_config.dma_erx = emac_dma_rx_chain_buf[0];
emac_config.dma_erx = emac_dma_rx_chain_buf;
emac_config.cnt_rx = 0;
emac_config.cur_rx = 0;
emac_config.dirty_rx = 0;
p = emac_dma_rx_chain_buf[0];
dma_phy = (uint32_t)(emac_config.dma_erx);
p = emac_config.dma_erx;
for (i = 0; i < (DMA_RX_BUF_NUM - 1); i++) {
dma_phy += sizeof(dma_extended_desc_t);
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
/* point to the buffer */
p->basic.desc3 = (uint32_t)(emac_dma_rx_chain_buf[i + 1]);
/* point to next descriptor */
p = emac_dma_rx_chain_buf[i + 1];
p->basic.desc3 = dma_phy;
p++;
}
/* point to the buffer */
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
/* point to first descriptor */
p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
}
@ -235,8 +235,7 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value)
}
REG_WRITE(EMAC_MIIDATA_REG, value);
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) |
((phy_num & 0x1f) << 11) | ((0x3) << 2));
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | ((0x3) << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
@ -250,8 +249,7 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) |
((phy_num & 0x1f) << 11) | (0x3 << 2));
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | (0x3 << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
}
value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff);
@ -259,12 +257,10 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
return value;
}
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value,
uint16_t value_mask, int timeout_ms)
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
{
unsigned start = xTaskGetTickCount();
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) /
portTICK_PERIOD_MS;
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
uint16_t current_value = 0;
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
@ -327,8 +323,7 @@ static void emac_set_user_config_data(eth_config_t *config)
}
emac_config.emac_flow_ctrl_enable = false;
#endif
emac_config.emac_phy_get_partner_pause_enable =
config->phy_get_partner_pause_enable;
emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
emac_config.emac_phy_power_enable = config->phy_power_enable;
}
@ -396,8 +391,7 @@ static esp_err_t emac_verify_args(void)
ret = ESP_FAIL;
}
if (emac_config.emac_flow_ctrl_enable == true &&
emac_config.emac_phy_get_partner_pause_enable == NULL) {
if (emac_config.emac_flow_ctrl_enable && !emac_config.emac_phy_get_partner_pause_enable) {
ESP_LOGE(TAG, "phy get partner pause enable func is null");
ret = ESP_FAIL;
}
@ -420,8 +414,8 @@ static void emac_process_tx(void)
xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY);
while ((uint32_t)(emac_dma_tx_chain_buf[emac_config.dirty_tx]) != cur_tx_desc) {
emac_clean_tx_desc(emac_dma_tx_chain_buf[emac_config.dirty_tx]);
while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx])) != cur_tx_desc) {
emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx]));
emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
emac_config.cnt_tx--;
@ -438,20 +432,19 @@ void esp_eth_free_rx_buf(void *buf)
{
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.cur_rx], (uint32_t)buf);
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t)buf);
emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM;
emac_config.cnt_rx--;
if (emac_config.cnt_rx < 0) {
ESP_LOGE(TAG, "emac rx buf err!!\n");
ESP_LOGE(TAG, "emac rx buf err");
}
emac_poll_rx_cmd();
xSemaphoreGiveRecursive(emac_rx_xMutex);
if (emac_config.emac_flow_ctrl_partner_support == true) {
if (emac_config.emac_flow_ctrl_partner_support) {
portENTER_CRITICAL(&g_emac_mux);
if (pause_send == true && emac_config.cnt_rx <
FLOW_CONTROL_LOW_WATERMARK) {
if (pause_send && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) {
emac_send_pause_zero_frame_enable();
pause_send = false;
}
@ -463,11 +456,11 @@ static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void)
{
uint32_t cnt = 0;
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
struct dma_extended_desc *cur_desc = (dma_extended_desc_t *)cur_rx_desc;
dma_extended_desc_t *cur_desc = (dma_extended_desc_t *)cur_rx_desc;
while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN && cnt < DMA_RX_BUF_NUM) {
cnt++;
cur_desc = (struct dma_extended_desc *)cur_desc->basic.desc3;
cur_desc = (dma_extended_desc_t *)cur_desc->basic.desc3;
}
return cnt;
}
@ -480,19 +473,15 @@ static void emac_process_rx(void)
}
uint32_t cur_rx_desc = emac_read_rx_cur_reg();
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc)) {
while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) {
//copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH), NULL);
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
(uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//if open this ,one intr can do many intrs ?
cur_rx_desc = emac_read_rx_cur_reg();
}
@ -507,21 +496,16 @@ static void emac_process_rx_unavail(void)
uint32_t dirty_cnt = 0;
while (dirty_cnt < DMA_RX_BUF_NUM) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
break;
}
dirty_cnt++;
//copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]),
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH), NULL);
emac_clean_rx_desc(emac_dma_rx_chain_buf[emac_config.dirty_rx],
(uint32_t)(emac_dma_rx_buf[emac_config.dirty_rx]));
emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
}
emac_enable_rx_intr();
@ -539,24 +523,20 @@ static void emac_process_rx_unavail(void)
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
break;
}
emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG, "emac rx unavail buf err !!\n");
ESP_LOGE(TAG, "emac rx buf full");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH), NULL);
}
emac_enable_rx_intr();
emac_enable_rx_unavail_intr();
@ -573,51 +553,41 @@ static void emac_process_rx(void)
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
if (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx])) !=
cur_rx_desc) {
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc) &&
if ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc)) {
while ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) &&
emac_config.cnt_rx < DMA_RX_BUF_NUM) {
emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG, "emac rx buf err!!\n");
ESP_LOGE(TAG, "emac rx buf full");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH), NULL);
cur_rx_desc = emac_read_rx_cur_reg();
}
} else {
if (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if ((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 &
EMAC_DESC_RX_OWN) == 0) {
if (!(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN)) {
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
break;
}
emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
ESP_LOGE(TAG, "emac rx buf err!!!\n");
ESP_LOGE(TAG, "emac rx buf full");
}
uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) %
DMA_RX_BUF_NUM;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
//copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >>
EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH), NULL);
}
}
}
@ -638,9 +608,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
if (event & EMAC_RECV_INT) {
emac_disable_rx_intr();
if (emac_config.emac_flow_ctrl_partner_support == true) {
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK &&
pause_send == false) {
if (emac_config.emac_flow_ctrl_partner_support) {
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && !pause_send) {
pause_send = true;
emac_send_pause_frame_enable();
}
@ -661,9 +630,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
static void emac_set_macaddr_reg(void)
{
REG_SET_FIELD(EMAC_ADDR0HIGH_REG, EMAC_ADDRESS0_HI, (emac_config.macaddr[5] << 8) | (emac_config.macaddr[4]));
REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[3] << 24) |
(emac_config.macaddr[2] << 16) | (emac_config.macaddr[1] << 8) |
(emac_config.macaddr[0]));
REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[3] << 24) | (emac_config.macaddr[2] << 16) |
(emac_config.macaddr[1] << 8) | (emac_config.macaddr[0]));
}
static void emac_check_phy_init(void)
@ -683,8 +651,8 @@ static void emac_check_phy_init(void)
emac_disable_flowctrl();
emac_config.emac_flow_ctrl_partner_support = false;
#else
if (emac_config.emac_flow_ctrl_enable == true) {
if (emac_config.emac_phy_get_partner_pause_enable() == true &&
if (emac_config.emac_flow_ctrl_enable) {
if (emac_config.emac_phy_get_partner_pause_enable() &&
emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
emac_enable_flowctrl();
emac_config.emac_flow_ctrl_partner_support = true;
@ -706,7 +674,7 @@ static void emac_process_link_updown(bool link_status)
emac_config.phy_link_up = link_status;
if (link_status == true) {
if (link_status) {
emac_check_phy_init();
ESP_LOGD(TAG, "eth link_up");
emac_enable_dma_tx();
@ -741,8 +709,7 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
esp_err_t ret = ESP_OK;
if (emac_config.emac_status != EMAC_RUNTIME_START) {
ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d",
emac_config.emac_status);
ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d", emac_config.emac_status);
ret = ESP_ERR_INVALID_STATE;
return ret;
}
@ -754,9 +721,9 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
goto _exit;
}
memcpy(emac_dma_tx_buf[emac_config.cur_tx], buf, size);
memcpy((void *)(emac_config.dma_etx[emac_config.cur_tx].basic.desc2), buf, size);
emac_setup_tx_desc(emac_dma_tx_chain_buf[emac_config.cur_tx], size);
emac_setup_tx_desc(&(emac_config.dma_etx[emac_config.cur_tx]), size);
emac_config.cnt_tx++;
emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM;
@ -771,7 +738,7 @@ _exit:
static void emac_init_default_data(void)
{
memset((uint8_t *)&emac_config, 0, sizeof(struct emac_config_data));
memset((void *)&emac_config, 0, sizeof(struct emac_config_data));
}
void emac_process_link_check(void)
@ -799,8 +766,7 @@ void emac_link_check_func(void *pv_parameters)
static bool emac_link_check_timer_init(void)
{
emac_timer = xTimerCreate("emac_timer",
(CONFIG_EMAC_CHECK_LINK_PERIOD_MS /
portTICK_PERIOD_MS),
(CONFIG_EMAC_CHECK_LINK_PERIOD_MS / portTICK_PERIOD_MS),
pdTRUE,
NULL,
emac_link_check_func);
@ -858,8 +824,6 @@ static void emac_start(void *param)
emac_mac_init();
//ptp TODO
emac_enable_intr();
emac_config.emac_status = EMAC_RUNTIME_START;
@ -869,8 +833,8 @@ static void emac_start(void *param)
esp_event_send(&evt);
//set a timer to check link up status
if (emac_link_check_timer_init() == true) {
if (emac_link_check_timer_start() != true) {
if (emac_link_check_timer_init()) {
if (!emac_link_check_timer_start()) {
cmd->err = EMAC_CMD_FAIL;
emac_link_check_timer_delete();
}
@ -913,7 +877,7 @@ esp_err_t esp_eth_enable(void)
}
if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) {
if (emac_ioctl(SIG_EMAC_START, (emac_par_t)(&post_cmd)) != 0) {
if (emac_ioctl(SIG_EMAC_START, (emac_par_t)(&post_cmd))) {
open_cmd.err = EMAC_CMD_FAIL;
goto cleanup;
}
@ -1103,16 +1067,16 @@ esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par)
esp_err_t esp_eth_init(eth_config_t *config)
{
int i = 0;
/* dynamically alloc memory for ethernet dma */
for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
emac_dma_rx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
emac_dma_rx_chain_buf = (dma_extended_desc_t *)heap_caps_malloc(sizeof(dma_extended_desc_t) * DMA_RX_BUF_NUM, MALLOC_CAP_DMA);
emac_dma_tx_chain_buf = (dma_extended_desc_t *)heap_caps_malloc(sizeof(dma_extended_desc_t) * DMA_TX_BUF_NUM, MALLOC_CAP_DMA);
for (i = 0; i < DMA_RX_BUF_NUM; i++) {
emac_dma_rx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_RX_BUF_SIZE, MALLOC_CAP_DMA);
}
for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
emac_dma_tx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), MALLOC_CAP_DMA);
for (i = 0; i < DMA_TX_BUF_NUM; i++) {
emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA);
}
esp_event_set_default_eth_handlers();
return esp_eth_init_internal(config);
}
@ -1126,7 +1090,7 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_init_default_data();
if (config != NULL) {
if (config) {
emac_set_user_config_data(config);
}
@ -1142,6 +1106,15 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
periph_module_enable(PERIPH_EMAC_MODULE);
if (emac_config.clock_mode != ETH_CLOCK_GPIO0_IN) {
#if CONFIG_SPIRAM_SUPPORT
if (esp_spiram_is_initialized()) {
ESP_LOGE(TAG, "GPIO16 and GPIO17 has been occupied by PSRAM, Only ETH_CLOCK_GPIO_IN is supported!");
ret = ESP_FAIL;
goto _exit;
} else {
ESP_LOGW(TAG, "GPIO16/17 is used for clock of EMAC, Please Make Sure you're not using PSRAM.");
}
#endif
// 50 MHz = 40MHz * (6 + 4) / (2 * (2 + 2) = 400MHz / 8
rtc_clk_apll_enable(1, 0, 0, 6, 2);
REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
@ -1151,15 +1124,13 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16");
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U,
FUNC_GPIO17_EMAC_CLK_OUT_180);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17");
}
}
emac_enable_clk(true);
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL,
EMAC_EX_PHY_INTF_RMII);
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII);
emac_dma_init();
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) {
@ -1191,10 +1162,14 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_rx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_tx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t));
xTaskCreate(emac_task, "emacT", EMAC_TASK_STACK_SIZE, NULL,
EMAC_TASK_PRIORITY, &emac_task_hdl);
xTaskCreate(emac_task,
"emacT",
EMAC_TASK_STACK_SIZE,
NULL,
EMAC_TASK_PRIORITY,
&emac_task_hdl);
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, NULL);
esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, emac_process_intr, NULL, &eth_intr_handle);
emac_config.emac_status = EMAC_RUNTIME_INIT;
@ -1205,6 +1180,7 @@ _exit:
esp_err_t esp_eth_deinit(void)
{
esp_err_t ret = ESP_FAIL;
int i = 0;
if (!emac_task_hdl) {
ret = ESP_ERR_INVALID_STATE;
@ -1223,21 +1199,21 @@ esp_err_t esp_eth_deinit(void)
periph_module_disable(PERIPH_EMAC_MODULE);
emac_config.emac_status = EMAC_RUNTIME_NOT_INIT;
/* free memory that dynamically allocted */
for (int i = 0; i < DMA_RX_BUF_NUM; i++) {
free(emac_dma_rx_chain_buf[i]);
/* free memory that dynamically allocated */
free(emac_dma_rx_chain_buf);
free(emac_dma_tx_chain_buf);
emac_dma_rx_chain_buf = NULL;
emac_dma_tx_chain_buf = NULL;
for (i = 0; i < DMA_RX_BUF_NUM; i++) {
free(emac_dma_rx_buf[i]);
emac_dma_rx_chain_buf[i] = NULL;
emac_dma_rx_buf[i] = NULL;
}
for (int i = 0; i < DMA_TX_BUF_NUM; i++) {
free(emac_dma_tx_chain_buf[i]);
for (i = 0; i < DMA_TX_BUF_NUM; i++) {
free(emac_dma_tx_buf[i]);
emac_dma_tx_chain_buf[i] = NULL;
emac_dma_tx_buf[i] = NULL;
}
esp_intr_free(eth_intr_handle);
ret = ESP_OK;
_exit:
return ret;
}

View file

@ -26,26 +26,16 @@
#define LAN8720_PHY_ID2_MASK 0xFFF0
/* LAN8720-specific registers */
#define SW_STRAP_CONTROL_REG (0x9)
#define SW_STRAP_CONFIG_DONE BIT(15)
#define AUTO_MDIX_ENABLE BIT(14)
#define AUTO_NEGOTIATION_ENABLE BIT(13)
#define AN_1 BIT(12)
#define AN_0 BIT(11)
#define LED_CFG BIT(10)
#define RMII_ENHANCED_MODE BIT(9)
#define DEFAULT_STRAP_CONFIG (AUTO_MDIX_ENABLE|AUTO_NEGOTIATION_ENABLE|AN_1|AN_0|LED_CFG)
#define PHY_SPECIAL_CONTROL_STATUS_REG (0x1f)
#define PHY_SPECIAL_CONTROL_STATUS_REG (0x1f)
#define AUTO_NEGOTIATION_DONE BIT(12)
#define DUPLEX_INDICATION_FULL BIT(4)
#define SPEED_INDICATION_100T BIT(3)
#define SPEED_INDICATION_10T BIT(2)
#define SPEED_DUPLEX_INDICATION_10T_HALF 0x04
#define SPEED_DUPLEX_INDICATION_10T_FULL 0x14
#define SPEED_DUPLEX_INDICATION_100T_HALF 0x08
#define SPEED_DUPLEX_INDICATION_100T_FULL 0x18
#define SPEED_INDICATION_100T BIT(3)
#define SPEED_INDICATION_10T BIT(2)
#define DUPLEX_INDICATION_FULL BIT(4)
static const char *TAG = "lan8720";
@ -82,7 +72,9 @@ eth_duplex_mode_t phy_lan8720_get_duplex_mode(void)
void phy_lan8720_power_enable(bool enable)
{
if (enable) {
esp_eth_smi_write(SW_STRAP_CONTROL_REG, DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
// TODO: only enable if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl();
}
@ -100,8 +92,9 @@ esp_err_t phy_lan8720_init(void)
res1 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_1_REG, LAN8720_PHY_ID1, UINT16_MAX, 1000);
res2 = esp_eth_smi_wait_value(MII_PHY_IDENTIFIER_2_REG, LAN8720_PHY_ID2, LAN8720_PHY_ID2_MASK, 1000);
esp_eth_smi_write(SW_STRAP_CONTROL_REG,
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE);
uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
ets_delay_us(300);

View file

@ -28,10 +28,10 @@ typedef enum {
ETH_MODE_MII,
} eth_mode_t;
typedef enum {
typedef enum {
ETH_CLOCK_GPIO0_IN = 0,
ETH_CLOCK_GPIO16_OUT = 2,
ETH_CLOCK_GPIO17_OUT = 3,
ETH_CLOCK_GPIO17_OUT = 3
} eth_clock_mode_t;
typedef enum {
@ -94,24 +94,22 @@ typedef void (*eth_phy_power_enable_func)(bool enable);
*
*/
typedef struct {
eth_phy_base_t phy_addr; /*!< phy base addr (0~31) */
eth_mode_t mac_mode; /*!< mac mode only support RMII now */
eth_clock_mode_t clock_mode; /*!< external/internal clock mode selecton */
eth_tcpip_input_func tcpip_input; /*!< tcpip input func */
eth_phy_func phy_init; /*!< phy init func */
eth_phy_check_link_func phy_check_link; /*!< phy check link func */
eth_phy_check_init_func phy_check_init; /*!< phy check init func */
eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */
eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */
eth_gpio_config_func gpio_config; /*!< gpio config func */
bool flow_ctrl_enable; /*!< flag of flow ctrl enable */
eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */
eth_phy_power_enable_func phy_power_enable; /*!< enable or disable phy power */
uint32_t reset_timeout_ms; /*!< timeout value for reset emac */
eth_phy_base_t phy_addr; /*!< phy base addr (0~31) */
eth_mode_t mac_mode; /*!< mac mode only support RMII now */
eth_clock_mode_t clock_mode; /*!< external/internal clock mode selecton */
eth_tcpip_input_func tcpip_input; /*!< tcpip input func */
eth_phy_func phy_init; /*!< phy init func */
eth_phy_check_link_func phy_check_link; /*!< phy check link func */
eth_phy_check_init_func phy_check_init; /*!< phy check init func */
eth_phy_get_speed_mode_func phy_get_speed_mode; /*!< phy check init func */
eth_phy_get_duplex_mode_func phy_get_duplex_mode; /*!< phy check init func */
eth_gpio_config_func gpio_config; /*!< gpio config func */
bool flow_ctrl_enable; /*!< flag of flow ctrl enable */
eth_phy_get_partner_pause_enable_func phy_get_partner_pause_enable; /*!< get partner pause enable */
eth_phy_power_enable_func phy_power_enable; /*!< enable or disable phy power */
uint32_t reset_timeout_ms; /*!< timeout value for reset emac */
} eth_config_t;
/**
* @brief Init ethernet mac
*

View file

@ -14,24 +14,40 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* This header contains register/bit masks for the standard
PHY MII registers that should be supported by all PHY models.
*/
#define MII_BASIC_MODE_CONTROL_REG (0x0)
#define MII_SOFTWARE_RESET BIT(15)
#define MII_BASIC_MODE_CONTROL_REG (0x0)
#define MII_SOFTWARE_RESET BIT(15)
#define MII_SPEED_SELECT BIT(13)
#define MII_AUTO_NEGOTIATION_ENABLE BIT(12)
#define MII_POWER_DOWN BIT(11)
#define MII_RESTART_AUTO_NEGOTIATION BIT(9)
#define MII_DUPLEX_MODE BIT(8)
#define MII_BASIC_MODE_STATUS_REG (0x1)
#define MII_AUTO_NEGOTIATION_COMPLETE BIT(5)
#define MII_LINK_STATUS BIT(2)
#define MII_BASIC_MODE_STATUS_REG (0x1)
#define MII_AUTO_NEGOTIATION_COMPLETE BIT(5)
#define MII_LINK_STATUS BIT(2)
#define MII_PHY_IDENTIFIER_1_REG (0x2)
#define MII_PHY_IDENTIFIER_2_REG (0x3)
#define MII_PHY_IDENTIFIER_1_REG (0x2)
#define MII_PHY_IDENTIFIER_2_REG (0x3)
#define MII_AUTO_NEG_ADVERTISEMENT_REG (0x4)
#define MII_ASM_DIR BIT(11)
#define MII_PAUSE BIT(10)
#define MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG (0x4)
#define MII_ASM_DIR BIT(11)
#define MII_PAUSE BIT(10)
#define MII_PHY_LINK_PARTNER_ABILITY_REG (0x5)
#define MII_PARTNER_ASM_DIR BIT(11)
#define MII_PARTNER_PAUSE BIT(10)
#define MII_PHY_LINK_PARTNER_ABILITY_REG (0x5)
#define MII_PARTNER_ASM_DIR BIT(11)
#define MII_PARTNER_PAUSE BIT(10)
/******************************legacy*******************************/
#define MII_AUTO_NEG_ADVERTISEMENT_REG MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG
#ifdef __cplusplus
}
#endif

View file

@ -196,7 +196,6 @@ if (netif->input(p, netif) != ERR_OK) {
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));
p->l2_owner = NULL;
pbuf_free(p);
}
#endif