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

Closes https://github.com/espressif/esp-idf/issues/2564
Closes https://github.com/espressif/esp-idf/issues/2620
Closes https://github.com/espressif/esp-idf/issues/2657
This commit is contained in:
morris 2018-10-15 20:35:05 +08:00
parent 364f033a49
commit b6d7675e60
7 changed files with 197 additions and 195 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 * @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 * memory with crap, so do not call after e.g. the heap allocator has stored important
* stuff in SPI RAM. * stuff in SPI RAM.
* *
@ -102,4 +102,14 @@ void esp_spiram_writeback_cache();
esp_err_t esp_spiram_reserve_dma_pool(size_t size); 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 #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. 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 #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_spiram_get_size()*8)/(1024*1024));
ESP_EARLY_LOGI(TAG, "SPI RAM mode: %s", PSRAM_SPEED == PSRAM_CACHE_F40M_S40M ? "flash 40m sram 40m" : \ 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" : \ 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 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. 2 banks after the 2 MiB mark.
*/ */
void IRAM_ATTR esp_spiram_writeback_cache() void IRAM_ATTR esp_spiram_writeback_cache()
{ {
int x; int x;
volatile int i=0; volatile int i=0;
@ -234,7 +234,7 @@ void IRAM_ATTR esp_spiram_writeback_cache()
if (!spiram_inited) return; 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. //disable it again on exit as well.
if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) { if (DPORT_REG_GET_BIT(DPORT_PRO_CACHE_CTRL_REG, DPORT_PRO_CACHE_ENABLE)==0) {
cache_was_disabled|=(1<<0); cache_was_disabled|=(1<<0);
@ -257,9 +257,9 @@ void IRAM_ATTR esp_spiram_writeback_cache()
} }
#else #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 32K cache for the lowest 2MiB of SPI flash and another 32K for the highest
2MiB. Clear this by reading from both regions. 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 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. we ever support external RAM chips of 2M or smaller, this may need adjusting.
*/ */
for (x=0; x<1024*64; x+=32) { for (x=0; x<1024*64; x+=32) {
@ -280,4 +280,15 @@ void IRAM_ATTR esp_spiram_writeback_cache()
#endif #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 #endif

View file

@ -14,8 +14,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
#include "rom/gpio.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_EMACDUPLEX);
REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACMII); REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACMII);
REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_EMACFESPEED); 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_eth.h"
#include "esp_intr_alloc.h" #include "esp_intr_alloc.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "esp_spiram.h"
#include "driver/periph_ctrl.h" #include "driver/periph_ctrl.h"
@ -59,8 +60,8 @@
static struct emac_config_data emac_config; 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_rx_chain_buf;
static dma_extended_desc_t *emac_dma_tx_chain_buf[DMA_TX_BUF_NUM]; 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_rx_buf[DMA_RX_BUF_NUM];
static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM]; static uint8_t *emac_dma_tx_buf[DMA_TX_BUF_NUM];
@ -93,7 +94,7 @@ void esp_eth_get_mac(uint8_t mac[6])
esp_err_t esp_eth_set_mac(const 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); memcpy(&(emac_config.macaddr[0]), mac, 6);
return ESP_OK; return ESP_OK;
} else { } else {
@ -106,22 +107,20 @@ eth_speed_mode_t esp_eth_get_speed(void)
return emac_config.emac_phy_get_speed_mode(); 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.desc1 = size & 0xfff;
tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | tx_desc->basic.desc0 = EMAC_DESC_TX_OWN | EMAC_DESC_INT_COMPL | EMAC_DESC_LAST_SEGMENT |
EMAC_DESC_LAST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_FIRST_SEGMENT | EMAC_DESC_SECOND_ADDR_CHAIN;
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.desc1 = 0;
tx_desc->basic.desc0 = 0; tx_desc->basic.desc0 = 0;
} }
static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc, static void emac_clean_rx_desc(dma_extended_desc_t *rx_desc, uint32_t buf_ptr)
uint32_t buf_ptr)
{ {
if (buf_ptr != 0) { if (buf_ptr != 0) {
rx_desc->basic.desc2 = buf_ptr; rx_desc->basic.desc2 = buf_ptr;
@ -184,46 +183,46 @@ static void emac_reset_dma_chain(void)
static void emac_init_dma_chain(void) static void emac_init_dma_chain(void)
{ {
int i; int i;
uint32_t dma_phy;
dma_extended_desc_t *p = NULL; dma_extended_desc_t *p = NULL;
//init tx chain //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.cnt_tx = 0;
emac_config.cur_tx = 0; emac_config.cur_tx = 0;
emac_config.dirty_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++) { for (i = 0; i < (DMA_TX_BUF_NUM - 1); i++) {
dma_phy += sizeof(dma_extended_desc_t);
emac_clean_tx_desc(p); emac_clean_tx_desc(p);
/* point to the buffer */
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]); p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
/* point to next descriptor */ p->basic.desc3 = dma_phy;
p->basic.desc3 = (uint32_t)(emac_dma_tx_chain_buf[i + 1]); p++;
p = emac_dma_tx_chain_buf[i + 1];
} }
emac_clean_tx_desc(p); emac_clean_tx_desc(p);
/* point to the buffer */
p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]); p->basic.desc2 = (uint32_t)(emac_dma_tx_buf[i]);
/* point to first descriptor */
p->basic.desc3 = (uint32_t)(emac_config.dma_etx); p->basic.desc3 = (uint32_t)(emac_config.dma_etx);
//init rx chain //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.cnt_rx = 0;
emac_config.cur_rx = 0; emac_config.cur_rx = 0;
emac_config.dirty_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++) { 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])); emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i]));
/* point to the buffer */ p->basic.desc3 = dma_phy;
p->basic.desc3 = (uint32_t)(emac_dma_rx_chain_buf[i + 1]); p++;
/* point to next descriptor */
p = emac_dma_rx_chain_buf[i + 1];
} }
/* point to the buffer */
emac_clean_rx_desc(p, (uint32_t)(emac_dma_rx_buf[i])); 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); p->basic.desc3 = (uint32_t)(emac_config.dma_erx);
} }
@ -235,8 +234,7 @@ void esp_eth_smi_write(uint32_t reg_num, uint16_t value)
} }
REG_WRITE(EMAC_MIIDATA_REG, value); REG_WRITE(EMAC_MIIDATA_REG, value);
REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | REG_WRITE(EMAC_GMIIADDR_REG, 0x3 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | ((0x3) << 2));
((phy_num & 0x1f) << 11) | ((0x3) << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
} }
@ -250,8 +248,7 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
} }
REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | REG_WRITE(EMAC_GMIIADDR_REG, 0x1 | ((reg_num & 0x1f) << 6) | ((phy_num & 0x1f) << 11) | (0x3 << 2));
((phy_num & 0x1f) << 11) | (0x3 << 2));
while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) { while (REG_GET_BIT(EMAC_GMIIADDR_REG, EMAC_MIIBUSY) == 1) {
} }
value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff); value = (REG_READ(EMAC_MIIDATA_REG) & 0xffff);
@ -259,12 +256,10 @@ uint16_t esp_eth_smi_read(uint32_t reg_num)
return value; return value;
} }
esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, esp_err_t esp_eth_smi_wait_value(uint32_t reg_num, uint16_t value, uint16_t value_mask, int timeout_ms)
uint16_t value_mask, int timeout_ms)
{ {
unsigned start = xTaskGetTickCount(); unsigned start = xTaskGetTickCount();
unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / unsigned timeout_ticks = (timeout_ms + portTICK_PERIOD_MS - 1) / portTICK_PERIOD_MS;
portTICK_PERIOD_MS;
uint16_t current_value = 0; uint16_t current_value = 0;
while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) { while (timeout_ticks == 0 || (xTaskGetTickCount() - start < timeout_ticks)) {
@ -327,8 +322,7 @@ static void emac_set_user_config_data(eth_config_t *config)
} }
emac_config.emac_flow_ctrl_enable = false; emac_config.emac_flow_ctrl_enable = false;
#endif #endif
emac_config.emac_phy_get_partner_pause_enable = emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
config->phy_get_partner_pause_enable;
emac_config.emac_phy_power_enable = config->phy_power_enable; emac_config.emac_phy_power_enable = config->phy_power_enable;
} }
@ -396,8 +390,7 @@ static esp_err_t emac_verify_args(void)
ret = ESP_FAIL; ret = ESP_FAIL;
} }
if (emac_config.emac_flow_ctrl_enable == true && if (emac_config.emac_flow_ctrl_enable && !emac_config.emac_phy_get_partner_pause_enable) {
emac_config.emac_phy_get_partner_pause_enable == NULL) {
ESP_LOGE(TAG, "phy get partner pause enable func is null"); ESP_LOGE(TAG, "phy get partner pause enable func is null");
ret = ESP_FAIL; ret = ESP_FAIL;
} }
@ -420,8 +413,8 @@ static void emac_process_tx(void)
xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY); xSemaphoreTakeRecursive(emac_tx_xMutex, portMAX_DELAY);
while ((uint32_t)(emac_dma_tx_chain_buf[emac_config.dirty_tx]) != cur_tx_desc) { while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx])) != cur_tx_desc) {
emac_clean_tx_desc(emac_dma_tx_chain_buf[emac_config.dirty_tx]); 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.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
emac_config.cnt_tx--; emac_config.cnt_tx--;
@ -438,20 +431,19 @@ void esp_eth_free_rx_buf(void *buf)
{ {
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY); 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.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM;
emac_config.cnt_rx--; emac_config.cnt_rx--;
if (emac_config.cnt_rx < 0) { 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(); emac_poll_rx_cmd();
xSemaphoreGiveRecursive(emac_rx_xMutex); 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); portENTER_CRITICAL(&g_emac_mux);
if (pause_send == true && emac_config.cnt_rx < if (pause_send && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) {
FLOW_CONTROL_LOW_WATERMARK) {
emac_send_pause_zero_frame_enable(); emac_send_pause_zero_frame_enable();
pause_send = false; pause_send = false;
} }
@ -463,11 +455,11 @@ static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void)
{ {
uint32_t cnt = 0; uint32_t cnt = 0;
uint32_t cur_rx_desc = emac_read_rx_cur_reg(); 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) { while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN && cnt < DMA_RX_BUF_NUM) {
cnt++; cnt++;
cur_desc = (struct dma_extended_desc *)cur_desc->basic.desc3; cur_desc = (dma_extended_desc_t *)cur_desc->basic.desc3;
} }
return cnt; return cnt;
} }
@ -480,19 +472,15 @@ static void emac_process_rx(void)
} }
uint32_t cur_rx_desc = emac_read_rx_cur_reg(); 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 //copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]), emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >> (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH), NULL);
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_clean_rx_desc(emac_dma_rx_chain_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));
(uint32_t)(emac_dma_rx_buf[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;
//if open this ,one intr can do many intrs ?
cur_rx_desc = emac_read_rx_cur_reg(); cur_rx_desc = emac_read_rx_cur_reg();
} }
@ -507,21 +495,16 @@ static void emac_process_rx_unavail(void)
uint32_t dirty_cnt = 0; uint32_t dirty_cnt = 0;
while (dirty_cnt < DMA_RX_BUF_NUM) { while (dirty_cnt < DMA_RX_BUF_NUM) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break; break;
} }
dirty_cnt++; dirty_cnt++;
//copy data to lwip //copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[emac_config.dirty_rx]), emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
(((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0) >> (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH), NULL);
EMAC_DESC_FRAME_LENGTH),
NULL);
emac_clean_rx_desc(emac_dma_rx_chain_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));
(uint32_t)(emac_dma_rx_buf[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;
} }
emac_enable_rx_intr(); emac_enable_rx_intr();
@ -539,24 +522,20 @@ static void emac_process_rx_unavail(void)
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY); xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break; break;
} }
emac_config.cnt_rx++; emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { 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; 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 //copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]), emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >> (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH), NULL);
EMAC_DESC_FRAME_LENGTH),
NULL);
} }
emac_enable_rx_intr(); emac_enable_rx_intr();
emac_enable_rx_unavail_intr(); emac_enable_rx_unavail_intr();
@ -573,51 +552,41 @@ static void emac_process_rx(void)
xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY); xSemaphoreTakeRecursive(emac_rx_xMutex, portMAX_DELAY);
if (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx])) != if ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc)) {
cur_rx_desc) { while ((((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx])) != cur_rx_desc) &&
while (((uint32_t)(emac_dma_rx_chain_buf[emac_config.dirty_rx]) != cur_rx_desc) &&
emac_config.cnt_rx < DMA_RX_BUF_NUM) { emac_config.cnt_rx < DMA_RX_BUF_NUM) {
emac_config.cnt_rx++; emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { 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; 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 //copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]), emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >> (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH), NULL);
EMAC_DESC_FRAME_LENGTH),
NULL);
cur_rx_desc = emac_read_rx_cur_reg(); cur_rx_desc = emac_read_rx_cur_reg();
} }
} else { } else {
if (emac_config.cnt_rx < DMA_RX_BUF_NUM) { if (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if ((emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 & if (!(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN)) {
EMAC_DESC_RX_OWN) == 0) {
while (emac_config.cnt_rx < DMA_RX_BUF_NUM) { while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) {
if (emac_dma_rx_chain_buf[emac_config.dirty_rx]->basic.desc0 == EMAC_DESC_RX_OWN) {
break; break;
} }
emac_config.cnt_rx++; emac_config.cnt_rx++;
if (emac_config.cnt_rx > DMA_RX_BUF_NUM) { 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; uint32_t tmp_dirty = emac_config.dirty_rx;
emac_config.dirty_rx = (emac_config.dirty_rx + 1) % emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
DMA_RX_BUF_NUM;
//copy data to lwip //copy data to lwip
emac_config.emac_tcpip_input((emac_dma_rx_buf[tmp_dirty]), emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[tmp_dirty].basic.desc2),
(((emac_dma_rx_chain_buf[tmp_dirty]->basic.desc0) >> (((emac_config.dma_erx[tmp_dirty].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) &
EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH), NULL);
EMAC_DESC_FRAME_LENGTH),
NULL);
} }
} }
} }
@ -638,9 +607,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
if (event & EMAC_RECV_INT) { if (event & EMAC_RECV_INT) {
emac_disable_rx_intr(); emac_disable_rx_intr();
if (emac_config.emac_flow_ctrl_partner_support == true) { if (emac_config.emac_flow_ctrl_partner_support) {
if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && !pause_send) {
pause_send == false) {
pause_send = true; pause_send = true;
emac_send_pause_frame_enable(); emac_send_pause_frame_enable();
} }
@ -661,9 +629,8 @@ static void IRAM_ATTR emac_process_intr(void *arg)
static void emac_set_macaddr_reg(void) 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_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) | REG_WRITE(EMAC_ADDR0LOW_REG, (emac_config.macaddr[3] << 24) | (emac_config.macaddr[2] << 16) |
(emac_config.macaddr[2] << 16) | (emac_config.macaddr[1] << 8) | (emac_config.macaddr[1] << 8) | (emac_config.macaddr[0]));
(emac_config.macaddr[0]));
} }
static void emac_check_phy_init(void) static void emac_check_phy_init(void)
@ -683,8 +650,8 @@ static void emac_check_phy_init(void)
emac_disable_flowctrl(); emac_disable_flowctrl();
emac_config.emac_flow_ctrl_partner_support = false; emac_config.emac_flow_ctrl_partner_support = false;
#else #else
if (emac_config.emac_flow_ctrl_enable == true) { if (emac_config.emac_flow_ctrl_enable) {
if (emac_config.emac_phy_get_partner_pause_enable() == true && if (emac_config.emac_phy_get_partner_pause_enable() &&
emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) { emac_config.emac_phy_get_duplex_mode() == ETH_MODE_FULLDUPLEX) {
emac_enable_flowctrl(); emac_enable_flowctrl();
emac_config.emac_flow_ctrl_partner_support = true; emac_config.emac_flow_ctrl_partner_support = true;
@ -706,7 +673,7 @@ static void emac_process_link_updown(bool link_status)
emac_config.phy_link_up = link_status; emac_config.phy_link_up = link_status;
if (link_status == true) { if (link_status) {
emac_check_phy_init(); emac_check_phy_init();
ESP_LOGD(TAG, "eth link_up"); ESP_LOGD(TAG, "eth link_up");
emac_enable_dma_tx(); emac_enable_dma_tx();
@ -741,8 +708,7 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
if (emac_config.emac_status != EMAC_RUNTIME_START) { if (emac_config.emac_status != EMAC_RUNTIME_START) {
ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d", ESP_LOGE(TAG, "tx netif is not ready, emac_status=%d", emac_config.emac_status);
emac_config.emac_status);
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
return ret; return ret;
} }
@ -754,9 +720,9 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
goto _exit; 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.cnt_tx++;
emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM; emac_config.cur_tx = (emac_config.cur_tx + 1) % DMA_TX_BUF_NUM;
@ -771,7 +737,7 @@ _exit:
static void emac_init_default_data(void) 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) void emac_process_link_check(void)
@ -799,8 +765,7 @@ void emac_link_check_func(void *pv_parameters)
static bool emac_link_check_timer_init(void) static bool emac_link_check_timer_init(void)
{ {
emac_timer = xTimerCreate("emac_timer", emac_timer = xTimerCreate("emac_timer",
(CONFIG_EMAC_CHECK_LINK_PERIOD_MS / (CONFIG_EMAC_CHECK_LINK_PERIOD_MS / portTICK_PERIOD_MS),
portTICK_PERIOD_MS),
pdTRUE, pdTRUE,
NULL, NULL,
emac_link_check_func); emac_link_check_func);
@ -858,8 +823,6 @@ static void emac_start(void *param)
emac_mac_init(); emac_mac_init();
//ptp TODO
emac_enable_intr(); emac_enable_intr();
emac_config.emac_status = EMAC_RUNTIME_START; emac_config.emac_status = EMAC_RUNTIME_START;
@ -869,8 +832,8 @@ static void emac_start(void *param)
esp_event_send(&evt); esp_event_send(&evt);
//set a timer to check link up status //set a timer to check link up status
if (emac_link_check_timer_init() == true) { if (emac_link_check_timer_init()) {
if (emac_link_check_timer_start() != true) { if (!emac_link_check_timer_start()) {
cmd->err = EMAC_CMD_FAIL; cmd->err = EMAC_CMD_FAIL;
emac_link_check_timer_delete(); emac_link_check_timer_delete();
} }
@ -913,7 +876,7 @@ esp_err_t esp_eth_enable(void)
} }
if (emac_config.emac_status != EMAC_RUNTIME_NOT_INIT) { 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; open_cmd.err = EMAC_CMD_FAIL;
goto cleanup; goto cleanup;
} }
@ -1103,16 +1066,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) esp_err_t esp_eth_init(eth_config_t *config)
{ {
int i = 0;
/* dynamically alloc memory for ethernet dma */ /* dynamically alloc memory for ethernet dma */
for (int i = 0; i < DMA_RX_BUF_NUM; i++) { 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_rx_chain_buf[i] = (struct dma_extended_desc *)heap_caps_malloc(sizeof(struct dma_extended_desc), 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); 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++) { for (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);
emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA); emac_dma_tx_buf[i] = (uint8_t *)heap_caps_malloc(DMA_TX_BUF_SIZE, MALLOC_CAP_DMA);
} }
esp_event_set_default_eth_handlers(); esp_event_set_default_eth_handlers();
return esp_eth_init_internal(config); return esp_eth_init_internal(config);
} }
@ -1126,7 +1089,7 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_init_default_data(); emac_init_default_data();
if (config != NULL) { if (config) {
emac_set_user_config_data(config); emac_set_user_config_data(config);
} }
@ -1142,6 +1105,15 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
periph_module_enable(PERIPH_EMAC_MODULE); periph_module_enable(PERIPH_EMAC_MODULE);
if (emac_config.clock_mode != ETH_CLOCK_GPIO0_IN) { 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 // 50 MHz = 40MHz * (6 + 4) / (2 * (2 + 2) = 400MHz / 8
rtc_clk_apll_enable(1, 0, 0, 6, 2); 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); REG_SET_FIELD(EMAC_EX_CLKOUT_CONF_REG, EMAC_EX_CLK_OUT_H_DIV_NUM, 0);
@ -1151,15 +1123,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); PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16"); ESP_LOGD(TAG, "EMAC 50MHz clock output on GPIO16");
} else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) { } else if (emac_config.clock_mode == ETH_CLOCK_GPIO17_OUT) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
FUNC_GPIO17_EMAC_CLK_OUT_180);
ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17"); ESP_LOGD(TAG, "EMAC 50MHz inverted clock output on GPIO17");
} }
} }
emac_enable_clk(true); emac_enable_clk(true);
REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, REG_SET_FIELD(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_PHY_INTF_SEL, EMAC_EX_PHY_INTF_RMII);
EMAC_EX_PHY_INTF_RMII);
emac_dma_init(); emac_dma_init();
if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) { if (emac_config.clock_mode == ETH_CLOCK_GPIO0_IN) {
@ -1191,8 +1161,12 @@ esp_err_t esp_eth_init_internal(eth_config_t *config)
emac_rx_xMutex = xSemaphoreCreateRecursiveMutex(); emac_rx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_tx_xMutex = xSemaphoreCreateRecursiveMutex(); emac_tx_xMutex = xSemaphoreCreateRecursiveMutex();
emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t)); emac_xqueue = xQueueCreate(EMAC_EVT_QNUM, sizeof(emac_event_t));
xTaskCreate(emac_task, "emacT", EMAC_TASK_STACK_SIZE, NULL, xTaskCreate(emac_task,
EMAC_TASK_PRIORITY, &emac_task_hdl); "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, NULL);
@ -1205,6 +1179,7 @@ _exit:
esp_err_t esp_eth_deinit(void) esp_err_t esp_eth_deinit(void)
{ {
esp_err_t ret = ESP_FAIL; esp_err_t ret = ESP_FAIL;
int i = 0;
if (!emac_task_hdl) { if (!emac_task_hdl) {
ret = ESP_ERR_INVALID_STATE; ret = ESP_ERR_INVALID_STATE;
@ -1224,20 +1199,19 @@ esp_err_t esp_eth_deinit(void)
emac_config.emac_status = EMAC_RUNTIME_NOT_INIT; emac_config.emac_status = EMAC_RUNTIME_NOT_INIT;
/* free memory that dynamically allocted */ /* free memory that dynamically allocted */
for (int i = 0; i < DMA_RX_BUF_NUM; i++) { free(emac_dma_rx_chain_buf);
free(emac_dma_rx_chain_buf[i]); 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]); free(emac_dma_rx_buf[i]);
emac_dma_rx_chain_buf[i] = NULL;
emac_dma_rx_buf[i] = NULL; emac_dma_rx_buf[i] = NULL;
} }
for (int i = 0; i < DMA_TX_BUF_NUM; i++) { for (i = 0; i < DMA_TX_BUF_NUM; i++) {
free(emac_dma_tx_chain_buf[i]);
free(emac_dma_tx_buf[i]); free(emac_dma_tx_buf[i]);
emac_dma_tx_chain_buf[i] = NULL;
emac_dma_tx_buf[i] = NULL; emac_dma_tx_buf[i] = NULL;
} }
ret = ESP_OK; ret = ESP_OK;
_exit: _exit:
return ret; return ret;
} }

View file

@ -26,26 +26,16 @@
#define LAN8720_PHY_ID2_MASK 0xFFF0 #define LAN8720_PHY_ID2_MASK 0xFFF0
/* LAN8720-specific registers */ /* 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 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_HALF 0x04
#define SPEED_DUPLEX_INDICATION_10T_FULL 0x14 #define SPEED_DUPLEX_INDICATION_10T_FULL 0x14
#define SPEED_DUPLEX_INDICATION_100T_HALF 0x08 #define SPEED_DUPLEX_INDICATION_100T_HALF 0x08
#define SPEED_DUPLEX_INDICATION_100T_FULL 0x18 #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"; 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) void phy_lan8720_power_enable(bool enable)
{ {
if (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 // TODO: only enable if config.flow_ctrl_enable == true
phy_mii_enable_flow_ctrl(); 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); 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); 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, uint32_t data = esp_eth_smi_read(MII_BASIC_MODE_CONTROL_REG);
DEFAULT_STRAP_CONFIG | SW_STRAP_CONFIG_DONE); data |= MII_AUTO_NEGOTIATION_ENABLE | MII_RESTART_AUTO_NEGOTIATION;
esp_eth_smi_write(MII_BASIC_MODE_CONTROL_REG, data);
ets_delay_us(300); ets_delay_us(300);

View file

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

View file

@ -14,24 +14,40 @@
#pragma once #pragma once
#ifdef __cplusplus
extern "C" {
#endif
/* This header contains register/bit masks for the standard /* This header contains register/bit masks for the standard
PHY MII registers that should be supported by all PHY models. PHY MII registers that should be supported by all PHY models.
*/ */
#define MII_BASIC_MODE_CONTROL_REG (0x0) #define MII_BASIC_MODE_CONTROL_REG (0x0)
#define MII_SOFTWARE_RESET BIT(15) #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_BASIC_MODE_STATUS_REG (0x1)
#define MII_AUTO_NEGOTIATION_COMPLETE BIT(5) #define MII_AUTO_NEGOTIATION_COMPLETE BIT(5)
#define MII_LINK_STATUS BIT(2) #define MII_LINK_STATUS BIT(2)
#define MII_PHY_IDENTIFIER_1_REG (0x2) #define MII_PHY_IDENTIFIER_1_REG (0x2)
#define MII_PHY_IDENTIFIER_2_REG (0x3) #define MII_PHY_IDENTIFIER_2_REG (0x3)
#define MII_AUTO_NEG_ADVERTISEMENT_REG (0x4) #define MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG (0x4)
#define MII_ASM_DIR BIT(11) #define MII_ASM_DIR BIT(11)
#define MII_PAUSE BIT(10) #define MII_PAUSE BIT(10)
#define MII_PHY_LINK_PARTNER_ABILITY_REG (0x5) #define MII_PHY_LINK_PARTNER_ABILITY_REG (0x5)
#define MII_PARTNER_ASM_DIR BIT(11) #define MII_PARTNER_ASM_DIR BIT(11)
#define MII_PARTNER_PAUSE BIT(10) #define MII_PARTNER_PAUSE BIT(10)
/******************************legacy*******************************/
#define MII_AUTO_NEG_ADVERTISEMENT_REG MII_AUTO_NEGOTIATION_ADVERTISEMENT_REG
#ifdef __cplusplus
}
#endif