mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 01:29:21 -04:00
hal/emac_hal: refactord emac_hal
This commit is contained in:
parent
e7f3099541
commit
fe354f1c50
@ -15,6 +15,7 @@
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_event_base.h"
|
||||
#include "hal/eth_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -38,12 +39,6 @@ extern "C" {
|
||||
*/
|
||||
#define ETH_HEADER_LEN (14)
|
||||
|
||||
/**
|
||||
* @brief Ethernet frame CRC length
|
||||
*
|
||||
*/
|
||||
#define ETH_CRC_LEN (4)
|
||||
|
||||
/**
|
||||
* @brief Optional 802.1q VLAN Tag length
|
||||
*
|
||||
@ -96,33 +91,6 @@ typedef enum {
|
||||
ETH_CMD_G_DUPLEX_MODE, /*!< Get Duplex mode */
|
||||
} esp_eth_io_cmd_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet link status
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_LINK_UP, /*!< Ethernet link is up */
|
||||
ETH_LINK_DOWN /*!< Ethernet link is down */
|
||||
} eth_link_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet speed
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_SPEED_10M, /*!< Ethernet speed is 10Mbps */
|
||||
ETH_SPEED_100M /*!< Ethernet speed is 100Mbps */
|
||||
} eth_speed_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet duplex mode
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_DUPLEX_HALF, /*!< Ethernet is in half duplex */
|
||||
ETH_DUPLEX_FULL /*!< Ethernet is in full duplex */
|
||||
} eth_duplex_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet mediator
|
||||
*
|
||||
|
@ -24,16 +24,19 @@
|
||||
#include "esp_system.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_private/esp_clk.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "hal/cpu_hal.h"
|
||||
#include "hal/emac.h"
|
||||
#include "hal/emac_hal.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "hal/emac_ll.h"
|
||||
|
||||
static const char *TAG = "esp.emac";
|
||||
|
||||
@ -80,15 +83,15 @@ static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_GOTO_ON_FALSE(!emac_hal_is_mii_busy(&emac->hal), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
|
||||
emac_hal_set_phy_data(&emac->hal, reg_value);
|
||||
ESP_GOTO_ON_FALSE(!emac_ll_is_mii_busy(emac->hal.mac_regs), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
|
||||
emac_ll_set_phy_data(emac->hal.mac_regs, reg_value);
|
||||
emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, true);
|
||||
/* polling the busy flag */
|
||||
uint32_t to = 0;
|
||||
bool busy = true;
|
||||
do {
|
||||
esp_rom_delay_us(100);
|
||||
busy = emac_hal_is_mii_busy(&emac->hal);
|
||||
busy = emac_ll_is_mii_busy(emac->hal.mac_regs);
|
||||
to += 100;
|
||||
} while (busy && to < PHY_OPERATION_TIMEOUT_US);
|
||||
ESP_GOTO_ON_FALSE(!busy, ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
|
||||
@ -102,19 +105,19 @@ static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr,
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(reg_value, ESP_ERR_INVALID_ARG, err, TAG, "can't set reg_value to null");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
ESP_GOTO_ON_FALSE(!emac_hal_is_mii_busy(&emac->hal), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
|
||||
ESP_GOTO_ON_FALSE(!emac_ll_is_mii_busy(emac->hal.mac_regs), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
|
||||
emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, false);
|
||||
/* polling the busy flag */
|
||||
uint32_t to = 0;
|
||||
bool busy = true;
|
||||
do {
|
||||
esp_rom_delay_us(100);
|
||||
busy = emac_hal_is_mii_busy(&emac->hal);
|
||||
busy = emac_ll_is_mii_busy(emac->hal.mac_regs);
|
||||
to += 100;
|
||||
} while (busy && to < PHY_OPERATION_TIMEOUT_US);
|
||||
ESP_GOTO_ON_FALSE(!busy, ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
|
||||
/* Store value */
|
||||
*reg_value = emac_hal_get_phy_data(&emac->hal);
|
||||
*reg_value = emac_ll_get_phy_data(emac->hal.mac_regs);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
@ -167,52 +170,32 @@ err:
|
||||
|
||||
static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_err_t ret = ESP_ERR_INVALID_ARG;
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
switch (speed) {
|
||||
case ETH_SPEED_10M:
|
||||
emac_hal_set_speed(&emac->hal, EMAC_SPEED_10M);
|
||||
ESP_LOGD(TAG, "working in 10Mbps");
|
||||
break;
|
||||
case ETH_SPEED_100M:
|
||||
emac_hal_set_speed(&emac->hal, EMAC_SPEED_100M);
|
||||
ESP_LOGD(TAG, "working in 100Mbps");
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown speed");
|
||||
break;
|
||||
if (speed >= ETH_SPEED_10M && speed < ETH_SPEED_MAX) {
|
||||
emac_ll_set_port_speed(emac->hal.mac_regs, speed);
|
||||
ESP_LOGD(TAG, "working in %dMbps", speed == ETH_SPEED_10M ? 10 : 100);
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
esp_err_t ret = ESP_ERR_INVALID_ARG;
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
switch (duplex) {
|
||||
case ETH_DUPLEX_HALF:
|
||||
emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_HALF);
|
||||
ESP_LOGD(TAG, "working in half duplex");
|
||||
break;
|
||||
case ETH_DUPLEX_FULL:
|
||||
emac_hal_set_duplex(&emac->hal, EMAC_DUPLEX_FULL);
|
||||
ESP_LOGD(TAG, "working in full duplex");
|
||||
break;
|
||||
default:
|
||||
ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown duplex");
|
||||
break;
|
||||
if (duplex == ETH_DUPLEX_HALF || duplex == ETH_DUPLEX_FULL) {
|
||||
emac_ll_set_duplex(emac->hal.mac_regs, duplex);
|
||||
ESP_LOGD(TAG, "working in %s duplex", duplex == ETH_DUPLEX_HALF ? "half" : "full");
|
||||
return ESP_OK;
|
||||
}
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t emac_esp32_set_promiscuous(esp_eth_mac_t *mac, bool enable)
|
||||
{
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
emac_hal_set_promiscuous(&emac->hal, enable);
|
||||
emac_ll_promiscuous_mode_enable(emac->hal.mac_regs, enable);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@ -293,9 +276,9 @@ static void emac_esp32_rx_task(void *arg)
|
||||
#if CONFIG_ETH_SOFT_FLOW_CONTROL
|
||||
// we need to do extra checking of remained frames in case there are no unhandled frames left, but pause frame is still undergoing
|
||||
if ((emac->free_rx_descriptor < emac->flow_control_low_water_mark) && emac->do_flow_ctrl && emac->frames_remain) {
|
||||
emac_hal_send_pause_frame(&emac->hal, true);
|
||||
emac_ll_pause_frame_enable(emac->hal.ext_regs, true);
|
||||
} else if ((emac->free_rx_descriptor > emac->flow_control_high_water_mark) || !emac->frames_remain) {
|
||||
emac_hal_send_pause_frame(&emac->hal, false);
|
||||
emac_ll_pause_frame_enable(emac->hal.ext_regs, false);
|
||||
}
|
||||
#endif
|
||||
} while (emac->frames_remain);
|
||||
@ -320,30 +303,93 @@ static void emac_esp32_init_smi_gpio(emac_esp32_t *emac)
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
static void emac_config_apll_clock(void)
|
||||
{
|
||||
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
|
||||
rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
|
||||
switch (rtc_xtal_freq) {
|
||||
case RTC_XTAL_FREQ_40M: // Recommended
|
||||
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
|
||||
/* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
|
||||
rtc_clk_apll_enable(true, 0, 0, 6, 2);
|
||||
break;
|
||||
case RTC_XTAL_FREQ_26M:
|
||||
/* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
|
||||
/* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
|
||||
rtc_clk_apll_enable(true, 39, 118, 15, 3);
|
||||
break;
|
||||
case RTC_XTAL_FREQ_24M:
|
||||
/* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
|
||||
/* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
|
||||
rtc_clk_apll_enable(true, 255, 255, 12, 2);
|
||||
break;
|
||||
default: // Assume we have a 40M xtal
|
||||
rtc_clk_apll_enable(true, 0, 0, 6, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
esp_eth_mediator_t *eth = emac->eth;
|
||||
/* enable peripheral clock */
|
||||
/* enable APB to access Ethernet peripheral registers */
|
||||
periph_module_enable(PERIPH_EMAC_MODULE);
|
||||
|
||||
/* init clock, config gpio, etc */
|
||||
emac_hal_lowlevel_init(&emac->hal);
|
||||
#if CONFIG_ETH_PHY_INTERFACE_MII
|
||||
/* MII interface GPIO initialization */
|
||||
emac_hal_iomux_init_mii();
|
||||
/* Enable MII clock */
|
||||
emac_ll_clock_enable_mii(emac->hal.ext_regs);
|
||||
#elif CONFIG_ETH_PHY_INTERFACE_RMII
|
||||
/* RMII interface GPIO initialization */
|
||||
emac_hal_iomux_init_rmii();
|
||||
/* If ref_clk is configured as input */
|
||||
#if CONFIG_ETH_RMII_CLK_INPUT
|
||||
#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
|
||||
emac_hal_iomux_rmii_clk_input();
|
||||
#else
|
||||
#error "ESP32 EMAC only support input RMII clock to GPIO0"
|
||||
#endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0
|
||||
emac_ll_clock_enable_rmii_input(emac->hal.ext_regs);
|
||||
#endif // CONFIG_ETH_RMII_CLK_INPUT
|
||||
|
||||
/* If ref_clk is configured as output */
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
|
||||
emac_hal_iomux_rmii_clk_ouput(0);
|
||||
/* Choose the APLL clock1 to output on specific GPIO */
|
||||
REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 6);
|
||||
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 16
|
||||
emac_hal_iomux_rmii_clk_ouput(16);
|
||||
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 17
|
||||
emac_hal_iomux_rmii_clk_ouput(17);
|
||||
#endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
|
||||
/* Enable RMII clock */
|
||||
emac_ll_clock_enable_rmii_output(emac->hal.ext_regs);
|
||||
emac_config_apll_clock();
|
||||
#endif // CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
#endif // CONFIG_ETH_PHY_INTERFACE_MII
|
||||
|
||||
/* init gpio used by smi interface */
|
||||
emac_esp32_init_smi_gpio(emac);
|
||||
ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
|
||||
/* software reset */
|
||||
emac_hal_reset(&emac->hal);
|
||||
emac_ll_reset(emac->hal.dma_regs);
|
||||
uint32_t to = 0;
|
||||
for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
|
||||
if (emac_hal_is_reset_done(&emac->hal)) {
|
||||
if (emac_ll_is_reset_done(emac->hal.dma_regs)) {
|
||||
break;
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(to < emac->sw_reset_timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "reset timeout");
|
||||
/* set smi clock */
|
||||
emac_hal_set_csr_clock_range(&emac->hal);
|
||||
emac_hal_set_csr_clock_range(&emac->hal, esp_clk_apb_freq());
|
||||
/* reset descriptor chain */
|
||||
emac_hal_reset_desc_chain(&emac->hal);
|
||||
/* init mac registers by default */
|
||||
@ -414,15 +460,23 @@ static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
|
||||
}
|
||||
|
||||
// To achieve a better performance, we put the ISR always in IRAM
|
||||
IRAM_ATTR void emac_esp32_isr_handler(void *args)
|
||||
IRAM_ATTR void emac_isr_default_handler(void *args)
|
||||
{
|
||||
emac_hal_context_t *hal = (emac_hal_context_t *)args;
|
||||
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
|
||||
emac_hal_isr(args);
|
||||
if (emac->isr_need_yield) {
|
||||
emac->isr_need_yield = false;
|
||||
portYIELD_FROM_ISR();
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
uint32_t intr_stat = emac_ll_get_intr_status(hal->dma_regs);
|
||||
emac_ll_clear_corresponding_intr(hal->dma_regs, intr_stat);
|
||||
|
||||
#if EMAC_LL_CONFIG_ENABLE_INTR_MASK & EMAC_LL_INTR_RECEIVE_ENABLE
|
||||
if (intr_stat & EMAC_LL_DMA_RECEIVE_FINISH_INTR) {
|
||||
/* notify receive task */
|
||||
vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
|
||||
if (high_task_wakeup == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
|
||||
@ -485,10 +539,10 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
|
||||
/* Interrupt configuration */
|
||||
if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
|
||||
ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM,
|
||||
emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl));
|
||||
emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
|
||||
} else {
|
||||
ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0,
|
||||
emac_esp32_isr_handler, &emac->hal, &(emac->intr_hdl));
|
||||
emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed");
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
@ -530,39 +584,3 @@ err:
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
IRAM_ATTR void emac_hal_rx_complete_cb(void *arg)
|
||||
{
|
||||
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
|
||||
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
|
||||
BaseType_t high_task_wakeup;
|
||||
/* notify receive task */
|
||||
vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
|
||||
if (high_task_wakeup == pdTRUE) {
|
||||
emac->isr_need_yield = true;
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void emac_hal_rx_unavail_cb(void *arg)
|
||||
{
|
||||
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
|
||||
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
|
||||
BaseType_t high_task_wakeup;
|
||||
/* notify receive task */
|
||||
vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
|
||||
if (high_task_wakeup == pdTRUE) {
|
||||
emac->isr_need_yield = true;
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void emac_hal_rx_early_cb(void *arg)
|
||||
{
|
||||
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
|
||||
emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
|
||||
BaseType_t high_task_wakeup;
|
||||
/* notify receive task */
|
||||
vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
|
||||
if (high_task_wakeup == pdTRUE) {
|
||||
emac->isr_need_yield = true;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ if(NOT BOOTLOADER_BUILD)
|
||||
"esp32/touch_sensor_hal.c"
|
||||
"esp32/gpio_hal_workaround.c")
|
||||
if(NOT BOOTLOADER_BUILD AND CONFIG_ETH_USE_ESP32_EMAC)
|
||||
list(APPEND srcs "esp32/emac_hal.c")
|
||||
list(APPEND srcs "emac_hal.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
@ -5,9 +5,9 @@ COMPONENT_ADD_LDFRAGMENTS += linker.lf
|
||||
COMPONENT_OBJEXCLUDE += ./spi_slave_hd_hal.o ./spi_flash_hal_gpspi.o ./spi_slave_hd_hal.o ./ds_hal.o ./gdma_hal.o ./lcd_hal.o ./systimer_hal.o ./usb_hal.o ./usbh_hal.o
|
||||
|
||||
ifndef CONFIG_ETH_USE_ESP32_EMAC
|
||||
COMPONENT_OBJEXCLUDE += esp32/emac_hal.o
|
||||
COMPONENT_OBJEXCLUDE += ./emac_hal.o
|
||||
endif
|
||||
|
||||
ifdef IS_BOOTLOADER_BUILD
|
||||
COMPONENT_OBJEXCLUDE += esp32/emac_hal.o
|
||||
COMPONENT_OBJEXCLUDE += ./emac_hal.o
|
||||
endif
|
||||
|
514
components/hal/emac_hal.c
Normal file
514
components/hal/emac_hal.c
Normal file
@ -0,0 +1,514 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "hal/emac_hal.h"
|
||||
#include "hal/emac_ll.h"
|
||||
#include "hal/gpio_ll.h"
|
||||
|
||||
#define ETH_CRC_LENGTH (4)
|
||||
|
||||
void emac_hal_iomux_init_mii(void)
|
||||
{
|
||||
/* TX_CLK to GPIO0 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
|
||||
/* TX_EN to GPIO21 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
|
||||
/* TXD0 to GPIO19 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
|
||||
/* TXD1 to GPIO22 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
|
||||
/* TXD2 to MTMS */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_MTMS_U, FUNC_MTMS_EMAC_TXD2);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[14]);
|
||||
/* TXD3 to MTDI */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_MTDI_U, FUNC_MTDI_EMAC_TXD3);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[12]);
|
||||
|
||||
/* RX_CLK to GPIO5 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5_EMAC_RX_CLK);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[5]);
|
||||
/* RX_DV to GPIO27 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
|
||||
/* RXD0 to GPIO25 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_EMAC_RXD0);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
|
||||
/* RXD1 to GPIO26 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_EMAC_RXD1);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
|
||||
/* RXD2 to U0TXD */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD_EMAC_RXD2);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[1]);
|
||||
/* RXD3 to MTDO */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_MTDO_U, FUNC_MTDO_EMAC_RXD3);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[15]);
|
||||
}
|
||||
|
||||
void emac_hal_iomux_rmii_clk_input(void)
|
||||
{
|
||||
/* REF_CLK(RMII mode) to GPIO0 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
|
||||
}
|
||||
|
||||
void emac_hal_iomux_rmii_clk_ouput(int num)
|
||||
{
|
||||
switch (num) {
|
||||
case 0:
|
||||
/* APLL clock output to GPIO0 (must be configured to 50MHz!) */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
|
||||
break;
|
||||
case 16:
|
||||
/* RMII CLK (50MHz) output to GPIO16 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
|
||||
break;
|
||||
case 17:
|
||||
/* RMII CLK (50MHz) output to GPIO17 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_iomux_init_rmii(void)
|
||||
{
|
||||
/* TX_EN to GPIO21 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
|
||||
/* TXD0 to GPIO19 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
|
||||
/* TXD1 to GPIO22 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
|
||||
|
||||
/* CRS_DV to GPIO27 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
|
||||
/* RXD0 to GPIO25 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_EMAC_RXD0);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
|
||||
/* RXD1 to GPIO26 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_EMAC_RXD1);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
|
||||
}
|
||||
|
||||
void emac_hal_iomux_init_tx_er(void)
|
||||
{
|
||||
/* TX_ER to GPIO4 */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4_EMAC_TX_ER);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[4]);
|
||||
}
|
||||
|
||||
void emac_hal_iomux_init_rx_er(void)
|
||||
{
|
||||
/* RX_ER to MTCK */
|
||||
gpio_ll_iomux_func_sel(PERIPHS_IO_MUX_MTCK_U, FUNC_MTCK_EMAC_RX_ER);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[13]);
|
||||
}
|
||||
|
||||
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
|
||||
uint8_t **rx_buf, uint8_t **tx_buf)
|
||||
{
|
||||
hal->dma_regs = &EMAC_DMA;
|
||||
hal->mac_regs = &EMAC_MAC;
|
||||
hal->ext_regs = &EMAC_EXT;
|
||||
hal->descriptors = descriptors;
|
||||
hal->rx_buf = rx_buf;
|
||||
hal->tx_buf = tx_buf;
|
||||
}
|
||||
|
||||
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal, int freq)
|
||||
{
|
||||
/* Tell MAC system clock Frequency, which will determine the frequency range of MDC(1MHz~2.5MHz) */
|
||||
if (freq >= 20 && freq < 35) {
|
||||
emac_ll_set_csr_clock_division(hal->mac_regs, 2); // CSR clock/16
|
||||
} else if (freq >= 35 && freq < 60) {
|
||||
emac_ll_set_csr_clock_division(hal->mac_regs, 3); // CSR clock/26
|
||||
} else if (freq >= 60 && freq < 100) {
|
||||
emac_ll_set_csr_clock_division(hal->mac_regs, 0); // CSR clock/42
|
||||
} else if (freq >= 100 && freq < 150) {
|
||||
emac_ll_set_csr_clock_division(hal->mac_regs, 1); // CSR clock/62
|
||||
} else if (freq > 150 && freq < 250) {
|
||||
emac_ll_set_csr_clock_division(hal->mac_regs, 4); // CSR clock/102
|
||||
} else {
|
||||
emac_ll_set_csr_clock_division(hal->mac_regs, 5); // CSR clock/124
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_reset_desc_chain(emac_hal_context_t *hal)
|
||||
{
|
||||
/* reset DMA descriptors */
|
||||
hal->rx_desc = (eth_dma_rx_descriptor_t *)(hal->descriptors);
|
||||
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->descriptors +
|
||||
sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM);
|
||||
/* init rx chain */
|
||||
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
|
||||
/* Set Own bit of the Rx descriptor Status: DMA */
|
||||
hal->rx_desc[i].RDES0.Own = 1;
|
||||
/* Set Buffer1 size and Second Address Chained bit */
|
||||
hal->rx_desc[i].RDES1.SecondAddressChained = 1;
|
||||
hal->rx_desc[i].RDES1.ReceiveBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* Enable Ethernet DMA Rx Descriptor interrupt */
|
||||
hal->rx_desc[i].RDES1.DisableInterruptOnComplete = 0;
|
||||
/* point to the buffer */
|
||||
hal->rx_desc[i].Buffer1Addr = (uint32_t)(hal->rx_buf[i]);
|
||||
/* point to next descriptor */
|
||||
hal->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc + i + 1);
|
||||
}
|
||||
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
|
||||
hal->rx_desc[CONFIG_ETH_DMA_RX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc);
|
||||
|
||||
/* init tx chain */
|
||||
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
|
||||
/* Set Second Address Chained bit */
|
||||
hal->tx_desc[i].TDES0.SecondAddressChained = 1;
|
||||
hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* Enable Ethernet DMA Tx Descriptor interrupt */
|
||||
hal->tx_desc[1].TDES0.InterruptOnComplete = 1;
|
||||
/* Enable Transmit Timestamp */
|
||||
hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1;
|
||||
/* point to the buffer */
|
||||
hal->tx_desc[i].Buffer1Addr = (uint32_t)(hal->tx_buf[i]);
|
||||
/* point to next descriptor */
|
||||
hal->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc + i + 1);
|
||||
}
|
||||
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
|
||||
hal->tx_desc[CONFIG_ETH_DMA_TX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc);
|
||||
|
||||
/* set base address of the first descriptor */
|
||||
emac_ll_set_rx_desc_addr(hal->dma_regs, (uint32_t)hal->rx_desc);
|
||||
emac_ll_set_tx_desc_addr(hal->dma_regs, (uint32_t)hal->tx_desc);
|
||||
}
|
||||
|
||||
void emac_hal_init_mac_default(emac_hal_context_t *hal)
|
||||
{
|
||||
/* MACCR Configuration */
|
||||
/* Enable the watchdog on the receiver, frame longer than 2048 Bytes is not allowed */
|
||||
emac_ll_watchdog_enable(hal->mac_regs, true);
|
||||
/* Enable the jabber timer on the transmitter, frame longer than 2048 Bytes is not allowed */
|
||||
emac_ll_jabber_enable(hal->mac_regs, true);
|
||||
/* minimum IFG between frames during transmission is 96 bit times */
|
||||
emac_ll_set_inter_frame_gap(hal->mac_regs, EMAC_LL_INTERFRAME_GAP_96BIT);
|
||||
/* Enable Carrier Sense During Transmission */
|
||||
emac_ll_carrier_sense_enable(hal->mac_regs, true);
|
||||
/* Select speed: port: 10/100 Mbps, here set default 100M, afterwards, will reset by auto-negotiation */
|
||||
emac_ll_set_port_speed(hal->mac_regs, ETH_SPEED_100M);;
|
||||
/* Allow the reception of frames when the TX_EN signal is asserted in Half-Duplex mode */
|
||||
emac_ll_recv_own_enable(hal->mac_regs, true);
|
||||
/* Disable internal loopback mode */
|
||||
emac_ll_loopback_enable(hal->mac_regs, false);
|
||||
/* Select duplex mode: here set default full duplex, afterwards, will reset by auto-negotiation */
|
||||
emac_ll_set_duplex(hal->mac_regs, ETH_DUPLEX_FULL);
|
||||
/* Select the checksum mode for received frame payload's TCP/UDP/ICMP headers */
|
||||
emac_ll_checksum_offload_mode(hal->mac_regs, ETH_CHECKSUM_HW);
|
||||
/* Enable MAC retry transmission when a colision occurs in half duplex mode */
|
||||
emac_ll_retry_enable(hal->mac_regs, true);
|
||||
/* MAC passes all incoming frames to host, without modifying them */
|
||||
emac_ll_auto_pad_crc_strip_enable(hal->mac_regs, false);
|
||||
/* Set Back-Off limit time before retry a transmittion after a collision */
|
||||
emac_ll_set_back_off_limit(hal->mac_regs, EMAC_LL_BACKOFF_LIMIT_10);
|
||||
/* Disable deferral check, MAC defers until the CRS signal goes inactive */
|
||||
emac_ll_deferral_check_enable(hal->mac_regs, false);
|
||||
/* Set preamble length 7 Bytes */
|
||||
emac_ll_set_preamble_length(hal->mac_regs, EMAC_LL_PREAMBLE_LENGTH_7);
|
||||
|
||||
/* MACFFR Configuration */
|
||||
/* Receiver module passes only those frames to the Application that pass the SA or DA address filter */
|
||||
emac_ll_receive_all_enable(hal->mac_regs, false);
|
||||
/* Disable source address filter */
|
||||
emac_ll_set_src_addr_filter(hal->mac_regs, EMAC_LL_SOURCE_ADDR_FILTER_DISABLE);
|
||||
emac_ll_sa_inverse_filter_enable(hal->mac_regs, false);
|
||||
/* MAC blocks all control frames */
|
||||
emac_ll_set_pass_ctrl_frame_mode(hal->mac_regs, EMAC_LL_CONTROL_FRAME_BLOCKALL);
|
||||
/* AFM module passes all received broadcast frames and multicast frames */
|
||||
emac_ll_broadcast_frame_enable(hal->mac_regs, true);
|
||||
emac_ll_pass_all_multicast_enable(hal->mac_regs, true);
|
||||
/* Address Check block operates in normal filtering mode for the DA address */
|
||||
emac_ll_da_inverse_filter_enable(hal->mac_regs, false);
|
||||
/* Disable Promiscuous Mode */
|
||||
emac_ll_promiscuous_mode_enable(hal->mac_regs, false);
|
||||
}
|
||||
|
||||
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable)
|
||||
{
|
||||
/* MACFCR Configuration */
|
||||
if (enable) {
|
||||
/* Pause time */
|
||||
emac_ll_set_pause_time(hal->mac_regs, EMAC_LL_PAUSE_TIME);
|
||||
/* Enable generation of Zero-Quanta Pause Control frames */
|
||||
emac_ll_zero_quanta_pause_enable(hal->mac_regs, true);
|
||||
/* Threshold of the PAUSE to be checked for automatic retransmission of PAUSE Frame */
|
||||
emac_ll_set_pause_low_threshold(hal->mac_regs, EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_28);
|
||||
/* Don't allow MAC detect Pause frames with MAC address0 unicast address and unique multicast address */
|
||||
emac_ll_unicast_pause_frame_detect_enable(hal->mac_regs, false);
|
||||
/* Enable MAC to decode the received Pause frame and disable its transmitter for a specific time */
|
||||
emac_ll_receive_flow_ctrl_enable(hal->mac_regs, true);
|
||||
/* Enable MAC to transmit Pause frames in full duplex mode or the MAC back-pressure operation in half duplex mode */
|
||||
emac_ll_transmit_flow_ctrl_enable(hal->mac_regs, true);
|
||||
} else {
|
||||
emac_ll_clear(hal->mac_regs);
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_init_dma_default(emac_hal_context_t *hal)
|
||||
{
|
||||
/* DMAOMR Configuration */
|
||||
/* Enable Dropping of TCP/IP Checksum Error Frames */
|
||||
emac_ll_drop_tcp_err_frame_enable(hal->dma_regs, true);
|
||||
/* Enable Receive Store Forward */
|
||||
emac_ll_recv_store_forward_enable(hal->dma_regs, true);
|
||||
/* Enable Flushing of Received Frames because of the unavailability of receive descriptors or buffers */
|
||||
emac_ll_flush_recv_frame_enable(hal->dma_regs, true);
|
||||
/* Enable Transmit Store Forward */
|
||||
emac_ll_trans_store_forward_enable(hal->dma_regs, true);
|
||||
/* Flush Transmit FIFO */
|
||||
emac_ll_flush_trans_fifo_enable(hal->dma_regs, true);
|
||||
/* Transmit Threshold Control */
|
||||
emac_ll_set_transmit_threshold(hal->dma_regs, EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_64);
|
||||
/* Disable Forward Error Frame */
|
||||
emac_ll_forward_err_frame_enable(hal->dma_regs, false);
|
||||
/* Disable forward undersized good frame */
|
||||
emac_ll_forward_undersized_good_frame_enable(hal->dma_regs, false);
|
||||
/* Receive Threshold Control */
|
||||
emac_ll_set_recv_threshold(hal->dma_regs, EMAC_LL_RECEIVE_THRESHOLD_CONTROL_64);
|
||||
/* Allow the DMA to process a second frame of Transmit data even before obtaining the status for the first frame */
|
||||
emac_ll_opt_second_frame_enable(hal->dma_regs, true);;
|
||||
|
||||
/* DMABMR Configuration */
|
||||
/* Enable Mixed Burst */
|
||||
emac_ll_mixed_burst_enable(hal->dma_regs, true);
|
||||
/* Enable Address Aligned Beates */
|
||||
emac_ll_addr_align_enable(hal->dma_regs, true);
|
||||
/* Use Separate PBL */
|
||||
emac_ll_use_separate_pbl_enable(hal->dma_regs, true);
|
||||
/* Set Rx/Tx DMA Burst Length */
|
||||
emac_ll_set_rx_dma_pbl(hal->dma_regs, EMAC_LL_DMA_BURST_LENGTH_32BEAT);
|
||||
emac_ll_set_prog_burst_len(hal->dma_regs, EMAC_LL_DMA_BURST_LENGTH_32BEAT);
|
||||
/* Enable Enhanced Descriptor,8 Words(32 Bytes) */
|
||||
emac_ll_enhance_desc_enable(hal->dma_regs, true);
|
||||
/* Specifies the number of word to skip between two unchained descriptors (Ring mode) */
|
||||
emac_ll_set_desc_skip_len(hal->dma_regs, 0);
|
||||
/* DMA Arbitration Scheme */
|
||||
emac_ll_fixed_arbitration_enable(hal->dma_regs, false);
|
||||
/* Set priority ratio in the weighted round-robin arbitration between Rx DMA and Tx DMA */
|
||||
emac_ll_set_priority_ratio(hal->dma_regs, EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1);
|
||||
}
|
||||
|
||||
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write)
|
||||
{
|
||||
/* Write the result value into the MII Address register */
|
||||
emac_ll_set_phy_addr(hal->mac_regs, phy_addr);
|
||||
/* Set the PHY register address */
|
||||
emac_ll_set_phy_reg(hal->mac_regs, phy_reg);
|
||||
/* Set as write mode */
|
||||
emac_ll_write_enable(hal->mac_regs, write);
|
||||
/* Set MII busy bit */
|
||||
emac_ll_set_busy(hal->mac_regs, true);
|
||||
|
||||
}
|
||||
|
||||
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr)
|
||||
{
|
||||
/* Make sure mac address is unicast type */
|
||||
if (!(mac_addr[0] & 0x01)) {
|
||||
emac_ll_set_addr(hal->mac_regs, mac_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_start(emac_hal_context_t *hal)
|
||||
{
|
||||
/* Enable Ethernet MAC and DMA Interrupt */
|
||||
emac_ll_enable_corresponding_intr(hal->dma_regs, EMAC_LL_CONFIG_ENABLE_INTR_MASK);
|
||||
|
||||
/* Enable transmit state machine of the MAC for transmission on the MII */
|
||||
emac_ll_transmit_enable(hal->mac_regs, true);
|
||||
/* Enable receive state machine of the MAC for reception from the MII */
|
||||
emac_ll_receive_enable(hal->mac_regs, true);
|
||||
/* Flush Transmit FIFO */
|
||||
emac_ll_flush_trans_fifo_enable(hal->dma_regs, true);
|
||||
/* Start DMA transmission */
|
||||
emac_ll_start_stop_dma_transmit(hal->dma_regs, true);
|
||||
/* Start DMA reception */
|
||||
emac_ll_start_stop_dma_receive(hal->dma_regs, true);
|
||||
|
||||
/* Clear all pending interrupts */
|
||||
emac_ll_clear_all_pending_intr(hal->dma_regs);
|
||||
}
|
||||
|
||||
void emac_hal_stop(emac_hal_context_t *hal)
|
||||
{
|
||||
/* Flush Transmit FIFO */
|
||||
emac_ll_flush_trans_fifo_enable(hal->dma_regs, true);
|
||||
/* Stop DMA transmission */
|
||||
emac_ll_start_stop_dma_transmit(hal->dma_regs, false);
|
||||
/* Stop DMA reception */
|
||||
emac_ll_start_stop_dma_receive(hal->dma_regs, false);
|
||||
/* Disable receive state machine of the MAC for reception from the MII */
|
||||
emac_ll_transmit_enable(hal->mac_regs, false);
|
||||
/* Disable transmit state machine of the MAC for transmission on the MII */
|
||||
emac_ll_receive_enable(hal->mac_regs, false);
|
||||
|
||||
/* Disable Ethernet MAC and DMA Interrupt */
|
||||
emac_ll_disable_all_intr(hal->dma_regs);
|
||||
}
|
||||
|
||||
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal)
|
||||
{
|
||||
return hal->tx_desc->TDES0.Own;
|
||||
}
|
||||
|
||||
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length)
|
||||
{
|
||||
/* Get the number of Tx buffers to use for the frame */
|
||||
uint32_t bufcount = 0;
|
||||
uint32_t lastlen = length;
|
||||
uint32_t sentout = 0;
|
||||
while (lastlen > CONFIG_ETH_DMA_BUFFER_SIZE) {
|
||||
lastlen -= CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
bufcount++;
|
||||
}
|
||||
if (lastlen) {
|
||||
bufcount++;
|
||||
}
|
||||
if (bufcount > CONFIG_ETH_DMA_TX_BUFFER_NUM) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
eth_dma_tx_descriptor_t *desc_iter = hal->tx_desc;
|
||||
/* A frame is transmitted in multiple descriptor */
|
||||
for (size_t i = 0; i < bufcount; i++) {
|
||||
/* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */
|
||||
if (desc_iter->TDES0.Own != EMAC_LL_DMADESC_OWNER_CPU) {
|
||||
goto err;
|
||||
}
|
||||
/* Clear FIRST and LAST segment bits */
|
||||
desc_iter->TDES0.FirstSegment = 0;
|
||||
desc_iter->TDES0.LastSegment = 0;
|
||||
desc_iter->TDES0.InterruptOnComplete = 0;
|
||||
if (i == 0) {
|
||||
/* Setting the first segment bit */
|
||||
desc_iter->TDES0.FirstSegment = 1;
|
||||
}
|
||||
if (i == (bufcount - 1)) {
|
||||
/* Setting the last segment bit */
|
||||
desc_iter->TDES0.LastSegment = 1;
|
||||
/* Enable transmit interrupt */
|
||||
desc_iter->TDES0.InterruptOnComplete = 1;
|
||||
/* Program size */
|
||||
desc_iter->TDES1.TransmitBuffer1Size = lastlen;
|
||||
/* copy data from uplayer stack buffer */
|
||||
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, lastlen);
|
||||
sentout += lastlen;
|
||||
} else {
|
||||
/* Program size */
|
||||
desc_iter->TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* copy data from uplayer stack buffer */
|
||||
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE);
|
||||
sentout += CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
}
|
||||
/* Point to next descriptor */
|
||||
desc_iter = (eth_dma_tx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
|
||||
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
|
||||
for (size_t i = 0; i < bufcount; i++) {
|
||||
hal->tx_desc->TDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
|
||||
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->tx_desc->Buffer2NextDescAddr);
|
||||
}
|
||||
emac_ll_transmit_poll_demand(hal->dma_regs, 0);
|
||||
return sentout;
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc)
|
||||
{
|
||||
eth_dma_rx_descriptor_t *desc_iter = NULL;
|
||||
eth_dma_rx_descriptor_t *first_desc = NULL;
|
||||
uint32_t used_descs = 0;
|
||||
uint32_t seg_count = 0;
|
||||
uint32_t ret_len = 0;
|
||||
uint32_t copy_len = 0;
|
||||
uint32_t write_len = 0;
|
||||
uint32_t frame_count = 0;
|
||||
|
||||
first_desc = hal->rx_desc;
|
||||
desc_iter = hal->rx_desc;
|
||||
/* Traverse descriptors owned by CPU */
|
||||
while ((desc_iter->RDES0.Own != EMAC_LL_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM) && !frame_count) {
|
||||
used_descs++;
|
||||
seg_count++;
|
||||
/* Last segment in frame */
|
||||
if (desc_iter->RDES0.LastDescriptor) {
|
||||
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
|
||||
ret_len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
|
||||
/* packets larger than expected will be truncated */
|
||||
copy_len = ret_len > size ? size : ret_len;
|
||||
/* update unhandled frame count */
|
||||
frame_count++;
|
||||
}
|
||||
/* First segment in frame */
|
||||
if (desc_iter->RDES0.FirstDescriptor) {
|
||||
first_desc = desc_iter;
|
||||
}
|
||||
/* point to next descriptor */
|
||||
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
/* there's at least one frame to process */
|
||||
if (frame_count) {
|
||||
/* check how many frames left to handle */
|
||||
while ((desc_iter->RDES0.Own != EMAC_LL_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
|
||||
used_descs++;
|
||||
if (desc_iter->RDES0.LastDescriptor) {
|
||||
frame_count++;
|
||||
}
|
||||
/* point to next descriptor */
|
||||
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
desc_iter = first_desc;
|
||||
for (size_t i = 0; i < seg_count - 1; i++) {
|
||||
used_descs--;
|
||||
write_len = copy_len < CONFIG_ETH_DMA_BUFFER_SIZE ? copy_len : CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* copy data to buffer */
|
||||
memcpy(buf, (void *)(desc_iter->Buffer1Addr), write_len);
|
||||
buf += write_len;
|
||||
copy_len -= write_len;
|
||||
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
|
||||
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
|
||||
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
memcpy(buf, (void *)(desc_iter->Buffer1Addr), copy_len);
|
||||
desc_iter->RDES0.Own = EMAC_LL_DMADESC_OWNER_DMA;
|
||||
/* update rxdesc */
|
||||
hal->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
/* poll rx demand */
|
||||
emac_ll_receive_poll_demand(hal->dma_regs, 0);
|
||||
frame_count--;
|
||||
used_descs--;
|
||||
}
|
||||
*frames_remain = frame_count;
|
||||
*free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs;
|
||||
return ret_len;
|
||||
}
|
@ -1,687 +0,0 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "hal/emac.h"
|
||||
#include "hal/gpio_hal.h"
|
||||
|
||||
#define ETH_CRC_LENGTH (4)
|
||||
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
static void emac_config_apll_clock(void)
|
||||
{
|
||||
/* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
|
||||
rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
|
||||
switch (rtc_xtal_freq) {
|
||||
case RTC_XTAL_FREQ_40M: // Recommended
|
||||
/* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
|
||||
/* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
|
||||
rtc_clk_apll_enable(true, 0, 0, 6, 2);
|
||||
break;
|
||||
case RTC_XTAL_FREQ_26M:
|
||||
/* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
|
||||
/* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
|
||||
rtc_clk_apll_enable(true, 39, 118, 15, 3);
|
||||
break;
|
||||
case RTC_XTAL_FREQ_24M:
|
||||
/* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
|
||||
/* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
|
||||
rtc_clk_apll_enable(true, 255, 255, 12, 2);
|
||||
break;
|
||||
default: // Assume we have a 40M xtal
|
||||
rtc_clk_apll_enable(true, 0, 0, 6, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
|
||||
uint8_t **rx_buf, uint8_t **tx_buf)
|
||||
{
|
||||
hal->dma_regs = &EMAC_DMA;
|
||||
hal->mac_regs = &EMAC_MAC;
|
||||
hal->ext_regs = &EMAC_EXT;
|
||||
hal->descriptors = descriptors;
|
||||
hal->rx_buf = rx_buf;
|
||||
hal->tx_buf = tx_buf;
|
||||
}
|
||||
|
||||
void emac_hal_lowlevel_init(emac_hal_context_t *hal)
|
||||
{
|
||||
/* GPIO configuration */
|
||||
/* TX_EN to GPIO21 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO21_U, FUNC_GPIO21_EMAC_TX_EN);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[21]);
|
||||
/* TXD0 to GPIO19 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_EMAC_TXD0);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[19]);
|
||||
/* TXD1 to GPIO22 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO22_U, FUNC_GPIO22_EMAC_TXD1);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[22]);
|
||||
/* RXD0 to GPIO25 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_EMAC_RXD0);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[25]);
|
||||
/* RXD1 to GPIO26 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_EMAC_RXD1);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[26]);
|
||||
/* CRS_DV to GPIO27 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO27_U, FUNC_GPIO27_EMAC_RX_DV);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[27]);
|
||||
#if CONFIG_ETH_RMII_CLK_INPUT
|
||||
#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
|
||||
/* RMII clock (50MHz) input to GPIO0 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_EMAC_TX_CLK);
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[0]);
|
||||
#else
|
||||
#error "ESP32 EMAC only support input RMII clock to GPIO0"
|
||||
#endif
|
||||
#endif
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
|
||||
/* APLL clock output to GPIO0 (must be configured to 50MHz!) */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[0]);
|
||||
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 16
|
||||
/* RMII CLK (50MHz) output to GPIO16 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO16_U, FUNC_GPIO16_EMAC_CLK_OUT);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[16]);
|
||||
#elif CONFIG_ETH_RMII_CLK_OUT_GPIO == 17
|
||||
/* RMII CLK (50MHz) output to GPIO17 */
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO17_U, FUNC_GPIO17_EMAC_CLK_OUT_180);
|
||||
PIN_INPUT_DISABLE(GPIO_PIN_MUX_REG[17]);
|
||||
#endif
|
||||
#endif // CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
/* Clock configuration */
|
||||
#if CONFIG_ETH_PHY_INTERFACE_MII
|
||||
hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 0;
|
||||
hal->ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1;
|
||||
hal->ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1;
|
||||
#elif CONFIG_ETH_PHY_INTERFACE_RMII
|
||||
hal->ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
|
||||
#if CONFIG_ETH_RMII_CLK_INPUT
|
||||
hal->ext_regs->ex_clk_ctrl.ext_en = 1;
|
||||
hal->ext_regs->ex_clk_ctrl.int_en = 0;
|
||||
hal->ext_regs->ex_oscclk_conf.clk_sel = 1;
|
||||
#elif CONFIG_ETH_RMII_CLK_OUTPUT
|
||||
hal->ext_regs->ex_clk_ctrl.ext_en = 0;
|
||||
hal->ext_regs->ex_clk_ctrl.int_en = 1;
|
||||
hal->ext_regs->ex_oscclk_conf.clk_sel = 0;
|
||||
emac_config_apll_clock();
|
||||
hal->ext_regs->ex_clkout_conf.div_num = 0;
|
||||
hal->ext_regs->ex_clkout_conf.h_div_num = 0;
|
||||
#if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
|
||||
/* Choose the APLL clock to output on GPIO */
|
||||
REG_WRITE(PIN_CTRL, 6);
|
||||
#endif // CONFIG_RMII_CLK_OUTPUT_GPIO0
|
||||
#endif // CONFIG_ETH_RMII_CLK_INPUT
|
||||
#endif // CONFIG_ETH_PHY_INTERFACE_MII
|
||||
}
|
||||
|
||||
void emac_hal_reset(emac_hal_context_t *hal)
|
||||
{
|
||||
hal->dma_regs->dmabusmode.sw_rst = 1;
|
||||
}
|
||||
|
||||
bool emac_hal_is_reset_done(emac_hal_context_t *hal)
|
||||
{
|
||||
return hal->dma_regs->dmabusmode.sw_rst ? false : true;
|
||||
}
|
||||
|
||||
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal)
|
||||
{
|
||||
/* Tell MAC system clock Frequency, which will determin the frequency range of MDC(1MHz~2.5MHz) */
|
||||
if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 20 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 35) {
|
||||
hal->mac_regs->emacgmiiaddr.miicsrclk = 2;
|
||||
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 35 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 60) {
|
||||
hal->mac_regs->emacgmiiaddr.miicsrclk = 3;
|
||||
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 60 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 100) {
|
||||
hal->mac_regs->emacgmiiaddr.miicsrclk = 0;
|
||||
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ >= 100 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 150) {
|
||||
hal->mac_regs->emacgmiiaddr.miicsrclk = 1;
|
||||
} else if (CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ > 150 && CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ < 250) {
|
||||
hal->mac_regs->emacgmiiaddr.miicsrclk = 4;
|
||||
} else {
|
||||
hal->mac_regs->emacgmiiaddr.miicsrclk = 5;
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_reset_desc_chain(emac_hal_context_t *hal)
|
||||
{
|
||||
/* reset DMA descriptors */
|
||||
hal->rx_desc = (eth_dma_rx_descriptor_t *)(hal->descriptors);
|
||||
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->descriptors +
|
||||
sizeof(eth_dma_rx_descriptor_t) * CONFIG_ETH_DMA_RX_BUFFER_NUM);
|
||||
/* init rx chain */
|
||||
for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
|
||||
/* Set Own bit of the Rx descriptor Status: DMA */
|
||||
hal->rx_desc[i].RDES0.Own = 1;
|
||||
/* Set Buffer1 size and Second Address Chained bit */
|
||||
hal->rx_desc[i].RDES1.SecondAddressChained = 1;
|
||||
hal->rx_desc[i].RDES1.ReceiveBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* Enable Ethernet DMA Rx Descriptor interrupt */
|
||||
hal->rx_desc[i].RDES1.DisableInterruptOnComplete = 0;
|
||||
/* point to the buffer */
|
||||
hal->rx_desc[i].Buffer1Addr = (uint32_t)(hal->rx_buf[i]);
|
||||
/* point to next descriptor */
|
||||
hal->rx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc + i + 1);
|
||||
}
|
||||
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
|
||||
hal->rx_desc[CONFIG_ETH_DMA_RX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->rx_desc);
|
||||
|
||||
/* init tx chain */
|
||||
for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
|
||||
/* Set Second Address Chained bit */
|
||||
hal->tx_desc[i].TDES0.SecondAddressChained = 1;
|
||||
hal->tx_desc[i].TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* Enable Ethernet DMA Tx Descriptor interrupt */
|
||||
hal->tx_desc[1].TDES0.InterruptOnComplete = 1;
|
||||
/* Enable Transmit Timestamp */
|
||||
hal->tx_desc[i].TDES0.TransmitTimestampEnable = 1;
|
||||
/* point to the buffer */
|
||||
hal->tx_desc[i].Buffer1Addr = (uint32_t)(hal->tx_buf[i]);
|
||||
/* point to next descriptor */
|
||||
hal->tx_desc[i].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc + i + 1);
|
||||
}
|
||||
/* For last descriptor, set next descriptor address register equal to the first descriptor base address */
|
||||
hal->tx_desc[CONFIG_ETH_DMA_TX_BUFFER_NUM - 1].Buffer2NextDescAddr = (uint32_t)(hal->tx_desc);
|
||||
|
||||
/* set base address of the first descriptor */
|
||||
hal->dma_regs->dmarxbaseaddr = (uint32_t)hal->rx_desc;
|
||||
hal->dma_regs->dmatxbaseaddr = (uint32_t)hal->tx_desc;
|
||||
}
|
||||
|
||||
void emac_hal_init_mac_default(emac_hal_context_t *hal)
|
||||
{
|
||||
/* MACCR Configuration */
|
||||
typeof(hal->mac_regs->gmacconfig) maccr = hal->mac_regs->gmacconfig;
|
||||
/* Enable the watchdog on the receiver, frame longer than 2048 Bytes is not allowed */
|
||||
maccr.watchdog = EMAC_WATCHDOG_ENABLE;
|
||||
/* Enable the jabber timer on the transmitter, frame longer than 2048 Bytes is not allowed */
|
||||
maccr.jabber = EMAC_JABBER_ENABLE;
|
||||
/* minimum IFG between frames during transmission is 96 bit times */
|
||||
maccr.interframegap = EMAC_INTERFRAME_GAP_96BIT;
|
||||
/* Enable Carrier Sense During Transmission */
|
||||
maccr.disablecrs = EMAC_CARRIERSENSE_ENABLE;
|
||||
/* Select port: 10/100 Mbps */
|
||||
maccr.mii = EMAC_PORT_10_100MBPS;
|
||||
/* Select speed: here set default 100M, afterwards, will reset by auto-negotiation */
|
||||
maccr.fespeed = EMAC_SPEED_100M;
|
||||
/* Allow the reception of frames when the TX_EN signal is asserted in Half-Duplex mode */
|
||||
maccr.rxown = EMAC_RECEIVE_OWN_ENABLE;
|
||||
/* Disable internal loopback mode */
|
||||
maccr.loopback = EMAC_LOOPBACK_DISABLE;
|
||||
/* Select duplex mode: here set default full duplex, afterwards, will reset by auto-negotiation */
|
||||
maccr.duplex = EMAC_DUPLEX_FULL;
|
||||
/* Select the checksum mode for received frame payload's TCP/UDP/ICMP headers */
|
||||
maccr.rxipcoffload = EMAC_CHECKSUM_HW;
|
||||
/* Enable MAC retry transmission when a colision occurs in half duplex mode */
|
||||
maccr.retry = EMAC_RETRY_TRANSMISSION_ENABLE;
|
||||
/* MAC passes all incoming frames to host, without modifying them */
|
||||
maccr.padcrcstrip = EMAC_AUTO_PAD_CRC_STRIP_DISABLE;
|
||||
/* Set Back-Off limit time before retry a transmittion after a collision */
|
||||
maccr.backofflimit = EMAC_BACKOFF_LIMIT_10;
|
||||
/* Disable deferral check, MAC defers until the CRS signal goes inactive */
|
||||
maccr.deferralcheck = EMAC_DEFERRAL_CHECK_DISABLE;
|
||||
/* Set preamble length 7 Bytes */
|
||||
maccr.pltf = EMAC_PREAMBLE_LENGTH_7;
|
||||
hal->mac_regs->gmacconfig = maccr;
|
||||
|
||||
/* MACFFR Configuration */
|
||||
typeof(hal->mac_regs->gmacff) macffr = hal->mac_regs->gmacff;
|
||||
/* Receiver module passes only those frames to the Application that pass the SA or DA address filter */
|
||||
macffr.receive_all = EMAC_RECEIVE_ALL_DISABLE;
|
||||
/* Disable source address filter */
|
||||
macffr.safe = EMAC_SOURCE_ADDR_FILTER_DISABLE;
|
||||
macffr.saif = 0;
|
||||
/* MAC blocks all control frames */
|
||||
macffr.pcf = EMAC_CONTROL_FRAME_BLOCKALL;
|
||||
/* AFM module passes all received broadcast frames and multicast frames */
|
||||
macffr.dbf = EMAC_RECEPT_BROADCAST_ENABLE;
|
||||
macffr.pam = 1;
|
||||
/* Address Check block operates in normal filtering mode for the DA address */
|
||||
macffr.daif = EMAC_DEST_ADDR_FILTER_NORMAL;
|
||||
/* Disable Promiscuous Mode */
|
||||
macffr.pmode = EMAC_PROMISCUOUS_DISABLE;
|
||||
hal->mac_regs->gmacff = macffr;
|
||||
}
|
||||
|
||||
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable)
|
||||
{
|
||||
/* MACFCR Configuration */
|
||||
typeof(hal->mac_regs->gmacfc) macfcr = hal->mac_regs->gmacfc;
|
||||
if (enable) {
|
||||
/* Pause time */
|
||||
macfcr.pause_time = EMAC_PAUSE_TIME;
|
||||
/* Enable generation of Zero-Quanta Pause Control frames */
|
||||
macfcr.dzpq = EMAC_ZERO_QUANTA_PAUSE_ENABLE;
|
||||
/* Threshold of the PAUSE to be checked for automatic retransmission of PAUSE Frame */
|
||||
macfcr.plt = EMAC_PAUSE_LOW_THRESHOLD_MINUS_28;
|
||||
/* Don't allow MAC detect Pause frames with MAC address0 unicast address and unique multicast address */
|
||||
macfcr.upfd = EMAC_UNICAST_PAUSE_DETECT_DISABLE;
|
||||
/* Enable MAC to decode the received Pause frame and disable its transmitter for a specific time */
|
||||
macfcr.rfce = EMAC_RECEIVE_FLOW_CONTROL_ENABLE;
|
||||
/* Enable MAC to transmit Pause frames in full duplex mode or the MAC back-pressure operation in half duplex mode */
|
||||
macfcr.tfce = EMAC_TRANSMIT_FLOW_CONTROL_ENABLE;
|
||||
} else {
|
||||
macfcr.val = 0;
|
||||
}
|
||||
hal->mac_regs->gmacfc = macfcr;
|
||||
}
|
||||
|
||||
void emac_hal_init_dma_default(emac_hal_context_t *hal)
|
||||
{
|
||||
/* DMAOMR Configuration */
|
||||
typeof(hal->dma_regs->dmaoperation_mode) dmaomr = hal->dma_regs->dmaoperation_mode;
|
||||
/* Enable Dropping of TCP/IP Checksum Error Frames */
|
||||
dmaomr.dis_drop_tcpip_err_fram = EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE;
|
||||
/* Enable Receive Store Forward */
|
||||
dmaomr.rx_store_forward = EMAC_RECEIVE_STORE_FORWARD_ENABLE;
|
||||
/* Enable Flushing of Received Frames because of the unavailability of receive descriptors or buffers */
|
||||
dmaomr.dis_flush_recv_frames = EMAC_FLUSH_RECEIVED_FRAME_ENABLE;
|
||||
/* Enable Transmit Store Forward */
|
||||
dmaomr.tx_str_fwd = EMAC_TRANSMIT_STORE_FORWARD_ENABLE;
|
||||
/* Flush Transmit FIFO */
|
||||
dmaomr.flush_tx_fifo = 1;
|
||||
/* Transmit Threshold Control */
|
||||
dmaomr.tx_thresh_ctrl = EMAC_TRANSMIT_THRESHOLD_CONTROL_64;
|
||||
/* Disable Forward Error Frame */
|
||||
dmaomr.fwd_err_frame = EMAC_FORWARD_ERROR_FRAME_DISABLE;
|
||||
/* Disable forward undersized good frame */
|
||||
dmaomr.fwd_under_gf = EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE;
|
||||
/* Receive Threshold Control */
|
||||
dmaomr.rx_thresh_ctrl = EMAC_RECEIVE_THRESHOLD_CONTROL_64;
|
||||
/* Allow the DMA to process a second frame of Transmit data even before obtaining the status for the first frame */
|
||||
dmaomr.opt_second_frame = EMAC_OPERATE_SECOND_FRAME_ENABLE;
|
||||
hal->dma_regs->dmaoperation_mode = dmaomr;
|
||||
|
||||
/* DMABMR Configuration */
|
||||
typeof(hal->dma_regs->dmabusmode) dmabmr = hal->dma_regs->dmabusmode;
|
||||
/* Enable Mixed Burst */
|
||||
dmabmr.dmamixedburst = EMAC_MIXED_BURST_ENABLE;
|
||||
/* Enable Address Aligned Beates */
|
||||
dmabmr.dmaaddralibea = EMAC_ADDR_ALIGN_BEATS_ENABLE;
|
||||
/* Use Separate PBL */
|
||||
dmabmr.use_sep_pbl = EMAC_USE_SEPARATE_PBL;
|
||||
/* Set Rx/Tx DMA Burst Length */
|
||||
dmabmr.rx_dma_pbl = EMAC_DMA_BURST_LENGTH_32BEAT;
|
||||
dmabmr.prog_burst_len = EMAC_DMA_BURST_LENGTH_32BEAT;
|
||||
/* Enable Enhanced Descriptor,8 Words(32 Bytes) */
|
||||
dmabmr.alt_desc_size = EMAC_ENHANCED_DESCRIPTOR_ENABLE;
|
||||
/* Specifies the number of word to skip between two unchained descriptors (Ring mode) */
|
||||
dmabmr.desc_skip_len = 0;
|
||||
/* DMA Arbitration Scheme */
|
||||
dmabmr.dma_arb_sch = EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN;
|
||||
/* Set priority ratio in the weighted round-robin arbitration between Rx DMA and Tx DMA */
|
||||
dmabmr.pri_ratio = EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1;
|
||||
hal->dma_regs->dmabusmode = dmabmr;
|
||||
}
|
||||
|
||||
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed)
|
||||
{
|
||||
hal->mac_regs->gmacconfig.fespeed = speed;
|
||||
}
|
||||
|
||||
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex)
|
||||
{
|
||||
hal->mac_regs->gmacconfig.duplex = duplex;
|
||||
}
|
||||
|
||||
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
hal->mac_regs->gmacff.pmode = 1;
|
||||
} else {
|
||||
hal->mac_regs->gmacff.pmode = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_send_pause_frame(emac_hal_context_t *hal, bool enable)
|
||||
{
|
||||
if (enable) {
|
||||
hal->ext_regs->ex_phyinf_conf.sbd_flowctrl = 1;
|
||||
} else {
|
||||
hal->ext_regs->ex_phyinf_conf.sbd_flowctrl = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool emac_hal_is_mii_busy(emac_hal_context_t *hal)
|
||||
{
|
||||
return hal->mac_regs->emacgmiiaddr.miibusy ? true : false;
|
||||
}
|
||||
|
||||
void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t phy_reg, bool write)
|
||||
{
|
||||
typeof(hal->mac_regs->emacgmiiaddr) macmiiar = hal->mac_regs->emacgmiiaddr;
|
||||
macmiiar.miidev = phy_addr;
|
||||
/* Set the PHY register address */
|
||||
macmiiar.miireg = phy_reg;
|
||||
if (write) {
|
||||
/* Set write mode */
|
||||
macmiiar.miiwrite = 1;
|
||||
} else {
|
||||
/* Set read mode */
|
||||
macmiiar.miiwrite = 0;
|
||||
}
|
||||
/* Set MII busy bit */
|
||||
macmiiar.miibusy = 1;
|
||||
/* Write the result value into the MII Address register */
|
||||
hal->mac_regs->emacgmiiaddr = macmiiar;
|
||||
}
|
||||
|
||||
void emac_hal_set_phy_data(emac_hal_context_t *hal, uint32_t reg_value)
|
||||
{
|
||||
hal->mac_regs->emacmiidata.mii_data = reg_value;
|
||||
}
|
||||
|
||||
uint32_t emac_hal_get_phy_data(emac_hal_context_t *hal)
|
||||
{
|
||||
return hal->mac_regs->emacmiidata.mii_data;
|
||||
}
|
||||
|
||||
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr)
|
||||
{
|
||||
/* Make sure mac address is unicast type */
|
||||
if (!(mac_addr[0] & 0x01)) {
|
||||
hal->mac_regs->emacaddr0high.address0_hi = (mac_addr[5] << 8) | mac_addr[4];
|
||||
hal->mac_regs->emacaddr0low = (mac_addr[3] << 24) | (mac_addr[2] << 16) | (mac_addr[1] << 8) | (mac_addr[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void emac_hal_start(emac_hal_context_t *hal)
|
||||
{
|
||||
typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode;
|
||||
typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig;
|
||||
|
||||
/* Enable Ethernet MAC and DMA Interrupt */
|
||||
hal->dma_regs->dmain_en.val = 0xFFFFFFFF;
|
||||
|
||||
/* Flush Transmit FIFO */
|
||||
opm.flush_tx_fifo = 1;
|
||||
/* Start DMA transmission */
|
||||
opm.start_stop_transmission_command = 1;
|
||||
/* Start DMA reception */
|
||||
opm.start_stop_rx = 1;
|
||||
/* Enable transmit state machine of the MAC for transmission on the MII */
|
||||
cfg.tx = 1;
|
||||
/* Enable receive state machine of the MAC for reception from the MII */
|
||||
cfg.rx = 1;
|
||||
|
||||
hal->dma_regs->dmaoperation_mode = opm;
|
||||
hal->mac_regs->gmacconfig = cfg;
|
||||
|
||||
/* Clear all pending interrupts */
|
||||
hal->dma_regs->dmastatus.val = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void emac_hal_stop(emac_hal_context_t *hal)
|
||||
{
|
||||
typeof(hal->dma_regs->dmaoperation_mode) opm = hal->dma_regs->dmaoperation_mode;
|
||||
typeof(hal->mac_regs->gmacconfig) cfg = hal->mac_regs->gmacconfig;
|
||||
|
||||
/* Flush Transmit FIFO */
|
||||
opm.flush_tx_fifo = 1;
|
||||
/* Stop DMA transmission */
|
||||
opm.start_stop_transmission_command = 0;
|
||||
/* Stop DMA reception */
|
||||
opm.start_stop_rx = 0;
|
||||
/* Disable receive state machine of the MAC for reception from the MII */
|
||||
cfg.rx = 0;
|
||||
/* Disable transmit state machine of the MAC for transmission on the MII */
|
||||
cfg.tx = 0;
|
||||
|
||||
hal->dma_regs->dmaoperation_mode = opm;
|
||||
hal->mac_regs->gmacconfig = cfg;
|
||||
|
||||
/* Disable Ethernet MAC and DMA Interrupt */
|
||||
hal->dma_regs->dmain_en.val = 0x0;
|
||||
}
|
||||
|
||||
uint32_t emac_hal_get_tx_desc_owner(emac_hal_context_t *hal)
|
||||
{
|
||||
return hal->tx_desc->TDES0.Own;
|
||||
}
|
||||
|
||||
uint32_t emac_hal_transmit_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t length)
|
||||
{
|
||||
/* Get the number of Tx buffers to use for the frame */
|
||||
uint32_t bufcount = 0;
|
||||
uint32_t lastlen = length;
|
||||
uint32_t sentout = 0;
|
||||
while (lastlen > CONFIG_ETH_DMA_BUFFER_SIZE) {
|
||||
lastlen -= CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
bufcount++;
|
||||
}
|
||||
if (lastlen) {
|
||||
bufcount++;
|
||||
}
|
||||
if (bufcount > CONFIG_ETH_DMA_TX_BUFFER_NUM) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
eth_dma_tx_descriptor_t *desc_iter = hal->tx_desc;
|
||||
/* A frame is transmitted in multiple descriptor */
|
||||
for (size_t i = 0; i < bufcount; i++) {
|
||||
/* Check if the descriptor is owned by the Ethernet DMA (when 1) or CPU (when 0) */
|
||||
if (desc_iter->TDES0.Own != EMAC_DMADESC_OWNER_CPU) {
|
||||
goto err;
|
||||
}
|
||||
/* Clear FIRST and LAST segment bits */
|
||||
desc_iter->TDES0.FirstSegment = 0;
|
||||
desc_iter->TDES0.LastSegment = 0;
|
||||
desc_iter->TDES0.InterruptOnComplete = 0;
|
||||
if (i == 0) {
|
||||
/* Setting the first segment bit */
|
||||
desc_iter->TDES0.FirstSegment = 1;
|
||||
}
|
||||
if (i == (bufcount - 1)) {
|
||||
/* Setting the last segment bit */
|
||||
desc_iter->TDES0.LastSegment = 1;
|
||||
/* Enable transmit interrupt */
|
||||
desc_iter->TDES0.InterruptOnComplete = 1;
|
||||
/* Program size */
|
||||
desc_iter->TDES1.TransmitBuffer1Size = lastlen;
|
||||
/* copy data from uplayer stack buffer */
|
||||
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, lastlen);
|
||||
sentout += lastlen;
|
||||
} else {
|
||||
/* Program size */
|
||||
desc_iter->TDES1.TransmitBuffer1Size = CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* copy data from uplayer stack buffer */
|
||||
memcpy((void *)(desc_iter->Buffer1Addr), buf + i * CONFIG_ETH_DMA_BUFFER_SIZE, CONFIG_ETH_DMA_BUFFER_SIZE);
|
||||
sentout += CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
}
|
||||
/* Point to next descriptor */
|
||||
desc_iter = (eth_dma_tx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
|
||||
/* Set Own bit of the Tx descriptor Status: gives the buffer back to ETHERNET DMA */
|
||||
for (size_t i = 0; i < bufcount; i++) {
|
||||
hal->tx_desc->TDES0.Own = EMAC_DMADESC_OWNER_DMA;
|
||||
hal->tx_desc = (eth_dma_tx_descriptor_t *)(hal->tx_desc->Buffer2NextDescAddr);
|
||||
}
|
||||
hal->dma_regs->dmatxpolldemand = 0;
|
||||
return sentout;
|
||||
err:
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t size, uint32_t *frames_remain, uint32_t *free_desc)
|
||||
{
|
||||
eth_dma_rx_descriptor_t *desc_iter = NULL;
|
||||
eth_dma_rx_descriptor_t *first_desc = NULL;
|
||||
uint32_t used_descs = 0;
|
||||
uint32_t seg_count = 0;
|
||||
uint32_t ret_len = 0;
|
||||
uint32_t copy_len = 0;
|
||||
uint32_t write_len = 0;
|
||||
uint32_t frame_count = 0;
|
||||
|
||||
first_desc = hal->rx_desc;
|
||||
desc_iter = hal->rx_desc;
|
||||
/* Traverse descriptors owned by CPU */
|
||||
while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM) && !frame_count) {
|
||||
used_descs++;
|
||||
seg_count++;
|
||||
/* Last segment in frame */
|
||||
if (desc_iter->RDES0.LastDescriptor) {
|
||||
/* Get the Frame Length of the received packet: substruct 4 bytes of the CRC */
|
||||
ret_len = desc_iter->RDES0.FrameLength - ETH_CRC_LENGTH;
|
||||
/* packets larger than expected will be truncated */
|
||||
copy_len = ret_len > size ? size : ret_len;
|
||||
/* update unhandled frame count */
|
||||
frame_count++;
|
||||
}
|
||||
/* First segment in frame */
|
||||
if (desc_iter->RDES0.FirstDescriptor) {
|
||||
first_desc = desc_iter;
|
||||
}
|
||||
/* point to next descriptor */
|
||||
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
/* there's at least one frame to process */
|
||||
if (frame_count) {
|
||||
/* check how many frames left to handle */
|
||||
while ((desc_iter->RDES0.Own != EMAC_DMADESC_OWNER_DMA) && (used_descs < CONFIG_ETH_DMA_RX_BUFFER_NUM)) {
|
||||
used_descs++;
|
||||
if (desc_iter->RDES0.LastDescriptor) {
|
||||
frame_count++;
|
||||
}
|
||||
/* point to next descriptor */
|
||||
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
desc_iter = first_desc;
|
||||
for (size_t i = 0; i < seg_count - 1; i++) {
|
||||
used_descs--;
|
||||
write_len = copy_len < CONFIG_ETH_DMA_BUFFER_SIZE ? copy_len : CONFIG_ETH_DMA_BUFFER_SIZE;
|
||||
/* copy data to buffer */
|
||||
memcpy(buf, (void *)(desc_iter->Buffer1Addr), write_len);
|
||||
buf += write_len;
|
||||
copy_len -= write_len;
|
||||
/* Set Own bit in Rx descriptors: gives the buffers back to DMA */
|
||||
desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA;
|
||||
desc_iter = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
}
|
||||
memcpy(buf, (void *)(desc_iter->Buffer1Addr), copy_len);
|
||||
desc_iter->RDES0.Own = EMAC_DMADESC_OWNER_DMA;
|
||||
/* update rxdesc */
|
||||
hal->rx_desc = (eth_dma_rx_descriptor_t *)(desc_iter->Buffer2NextDescAddr);
|
||||
/* poll rx demand */
|
||||
hal->dma_regs->dmarxpolldemand = 0;
|
||||
frame_count--;
|
||||
used_descs--;
|
||||
}
|
||||
*frames_remain = frame_count;
|
||||
*free_desc = CONFIG_ETH_DMA_RX_BUFFER_NUM - used_descs;
|
||||
return ret_len;
|
||||
}
|
||||
|
||||
IRAM_ATTR void emac_hal_isr(void *arg)
|
||||
{
|
||||
emac_hal_context_t *hal = (emac_hal_context_t *)arg;
|
||||
typeof(hal->dma_regs->dmastatus) dma_status = hal->dma_regs->dmastatus;
|
||||
hal->dma_regs->dmastatus.val = dma_status.val;
|
||||
/* DMA Normal Interrupt */
|
||||
if (dma_status.norm_int_summ) {
|
||||
/* Transmit Interrupt */
|
||||
if (dma_status.trans_int) {
|
||||
emac_hal_tx_complete_cb(arg);
|
||||
}
|
||||
/* Transmit Buffer Unavailable */
|
||||
if (dma_status.trans_buf_unavail) {
|
||||
emac_hal_tx_unavail_cb(arg);
|
||||
}
|
||||
/* Receive Interrupt */
|
||||
if (dma_status.recv_int) {
|
||||
emac_hal_rx_complete_cb(arg);
|
||||
}
|
||||
/* Early Receive Interrupt */
|
||||
if (dma_status.early_recv_int) {
|
||||
emac_hal_rx_early_cb(arg);
|
||||
}
|
||||
}
|
||||
/* DMA Abnormal Interrupt */
|
||||
if (dma_status.abn_int_summ) {
|
||||
/* Transmit Process Stopped */
|
||||
if (dma_status.trans_proc_stop) {
|
||||
}
|
||||
/* Transmit Jabber Timeout */
|
||||
if (dma_status.trans_jabber_to) {
|
||||
}
|
||||
/* Receive FIFO Overflow */
|
||||
if (dma_status.recv_ovflow) {
|
||||
}
|
||||
/* Transmit Underflow */
|
||||
if (dma_status.trans_undflow) {
|
||||
}
|
||||
/* Receive Buffer Unavailable */
|
||||
if (dma_status.recv_buf_unavail) {
|
||||
emac_hal_rx_unavail_cb(arg);
|
||||
}
|
||||
/* Receive Process Stopped */
|
||||
if (dma_status.recv_proc_stop) {
|
||||
}
|
||||
/* Receive Watchdog Timeout */
|
||||
if (dma_status.recv_wdt_to) {
|
||||
}
|
||||
/* Early Transmit Interrupt */
|
||||
if (dma_status.early_trans_int) {
|
||||
}
|
||||
/* Fatal Bus Error */
|
||||
if (dma_status.fatal_bus_err_int) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR __attribute__((weak)) void emac_hal_tx_complete_cb(void *arg)
|
||||
{
|
||||
// This is a weak function, do nothing by default
|
||||
// Upper code can rewrite this function
|
||||
// Note: you're in the interrupt context
|
||||
return;
|
||||
}
|
||||
|
||||
IRAM_ATTR __attribute__((weak)) void emac_hal_tx_unavail_cb(void *arg)
|
||||
{
|
||||
// This is a weak function, do nothing by default
|
||||
// Upper code can rewrite this function
|
||||
// Note: you're in the interrupt context
|
||||
return;
|
||||
}
|
||||
|
||||
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_complete_cb(void *arg)
|
||||
{
|
||||
// This is a weak function, do nothing by default
|
||||
// Upper code can rewrite this function
|
||||
// Note: you're in the interrupt context
|
||||
return;
|
||||
}
|
||||
|
||||
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_early_cb(void *arg)
|
||||
{
|
||||
// This is a weak function, do nothing by default
|
||||
// Upper code can rewrite this function
|
||||
// Note: you're in the interrupt context
|
||||
return;
|
||||
}
|
||||
|
||||
IRAM_ATTR __attribute__((weak)) void emac_hal_rx_unavail_cb(void *arg)
|
||||
{
|
||||
// This is a weak function, do nothing by default
|
||||
// Upper code can rewrite this function
|
||||
// Note: you're in the interrupt context
|
||||
return;
|
||||
}
|
596
components/hal/esp32/include/hal/emac_ll.h
Normal file
596
components/hal/esp32/include/hal/emac_ll.h
Normal file
@ -0,0 +1,596 @@
|
||||
// Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/*******************************************************************************
|
||||
* NOTICE
|
||||
* The hal is not public api, don't use in application code.
|
||||
* See readme.md in hal/include/hal/readme.md
|
||||
******************************************************************************/
|
||||
|
||||
// The LL layer for ESP32 eMAC register operations
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "hal/eth_types.h"
|
||||
#include "soc/emac_dma_struct.h"
|
||||
#include "soc/emac_mac_struct.h"
|
||||
#include "soc/emac_ext_struct.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Register configuration */
|
||||
#define EMAC_LL_INTERFRAME_GAP_96BIT (0)
|
||||
#define EMAC_LL_INTERFRAME_GAP_88BIT (1)
|
||||
#define EMAC_LL_INTERFRAME_GAP_80BIT (2)
|
||||
#define EMAC_LL_INTERFRAME_GAP_72BIT (3)
|
||||
#define EMAC_LL_INTERFRAME_GAP_64BIT (4)
|
||||
#define EMAC_LL_INTERFRAME_GAP_56BIT (5)
|
||||
#define EMAC_LL_INTERFRAME_GAP_48BIT (6)
|
||||
#define EMAC_LL_INTERFRAME_GAP_40BIT (7)
|
||||
|
||||
#define EMAC_LL_BACKOFF_LIMIT_10 (0)
|
||||
#define EMAC_LL_BACKOFF_LIMIT_8 (1)
|
||||
#define EMAC_LL_BACKOFF_LIMIT_4 (2)
|
||||
#define EMAC_LL_BACKOFF_LIMIT_1 (3)
|
||||
|
||||
#define EMAC_LL_PREAMBLE_LENGTH_7 (0)
|
||||
#define EMAC_LL_PREAMBLE_LENGTH_5 (1)
|
||||
#define EMAC_LL_PREAMBLE_LENGTH_3 (2)
|
||||
|
||||
#define EMAC_LL_SOURCE_ADDR_FILTER_DISABLE (0)
|
||||
#define EMAC_LL_SOURCE_ADDR_FILTER_NORMAL (2)
|
||||
#define EMAC_LL_SOURCE_ADDR_FILTER_INVERSE (3)
|
||||
|
||||
#define EMAC_LL_CONTROL_FRAME_BLOCKALL (0)
|
||||
#define EMAC_LL_CONTROL_FRAME_FORWARDALL_PAUSE (1)
|
||||
#define EMAC_LL_CONTROL_FRAME_FORWARDALL (2)
|
||||
#define EMAC_LL_CONTROL_FRAME_FORWARDFILT (3)
|
||||
|
||||
#define EMAC_LL_PAUSE_TIME 0x1648
|
||||
|
||||
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
|
||||
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
|
||||
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
|
||||
#define EMAC_LL_PAUSE_LOW_THRESHOLD_MINUS_256 (3)
|
||||
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_64 (0)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_128 (1)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_192 (2)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_256 (3)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_40 (4)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_32 (5)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_24 (6)
|
||||
#define EMAC_LL_TRANSMIT_THRESHOLD_CONTROL_16 (7)
|
||||
|
||||
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_64 (0)
|
||||
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_32 (1)
|
||||
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_96 (2)
|
||||
#define EMAC_LL_RECEIVE_THRESHOLD_CONTROL_128 (3)
|
||||
|
||||
#define EMAC_LL_DMA_BURST_LENGTH_1BEAT (1)
|
||||
#define EMAC_LL_DMA_BURST_LENGTH_2BEAT (2)
|
||||
#define EMAC_LL_DMA_BURST_LENGTH_4BEAT (4)
|
||||
#define EMAC_LL_DMA_BURST_LENGTH_8BEAT (8)
|
||||
#define EMAC_LL_DMA_BURST_LENGTH_16BEAT (16)
|
||||
#define EMAC_LL_DMA_BURST_LENGTH_32BEAT (32)
|
||||
|
||||
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
|
||||
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
|
||||
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
|
||||
#define EMAC_LL_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
|
||||
|
||||
/* PTP register bits */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
|
||||
#define EMAC_LL_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
|
||||
|
||||
#define EMAC_LL_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
|
||||
#define EMAC_LL_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
|
||||
#define EMAC_LL_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
|
||||
|
||||
#define EMAC_LL_DMADESC_OWNER_CPU (0)
|
||||
#define EMAC_LL_DMADESC_OWNER_DMA (1)
|
||||
|
||||
/* Interrupt flags (referring to dmastatus register in emac_dma_struct.h) */
|
||||
#define EMAC_LL_DMA_TRANSMIT_FINISH_INTR 0x00000001U
|
||||
#define EMAC_LL_DMA_TRANSMIT_STOP_INTR 0x00000002U
|
||||
#define EMAC_LL_DMA_TRANSMIT_BUFF_UNAVAILABLE_INTR 0x00000004U
|
||||
#define EMAC_LL_DMA_TRANSMIT_TIMEOUT_INTR 0x00000008U
|
||||
#define EMAC_LL_DMA_RECEIVE_OVERFLOW_INTR 0x00000010U
|
||||
#define EMAC_LL_DMA_TRANSMIT_UNDERFLOW_INTR 0x00000020U
|
||||
#define EMAC_LL_DMA_RECEIVE_FINISH_INTR 0x00000040U
|
||||
#define EMAC_LL_DMA_RECEIVE_BUFF_UNAVAILABLE_INTR 0x00000080U
|
||||
#define EMAC_LL_DMA_RECEIVE_STOP_INTR 0x00000100U
|
||||
#define EMAC_LL_DMA_RECEIVE_TIMEOUT_INTR 0x00000200U
|
||||
#define EMAC_LL_DMA_TRANSMIT_FIRST_BYTE_INTR 0x00000400U
|
||||
#define EMAC_LL_DMA_FATAL_BUS_ERROR_INRT 0x00001000U
|
||||
#define EMAC_LL_DMA_RECEIVE_FIRST_BYTE_INTR 0x00002000U
|
||||
#define EMAC_LL_DMA_ABNORMAL_INTR_SUMMARY 0x00004000U
|
||||
#define EMAC_LL_DMA_NORMAL_INTR_SUMMARY 0x00008000U
|
||||
#define EMAC_LL_DMA_POWER_MANAGE_INTR 0x10000000U
|
||||
#define EMAC_LL_DMA_TIMESTAMP_TRIGGER_INTR 0x20000000U
|
||||
|
||||
/* Interrupt enable (referring to dmain_en register in emac_dma_struct.h) */
|
||||
#define EMAC_LL_INTR_TRANSMIT_ENABLE 0x00000001U
|
||||
#define EMAC_LL_INTR_TRANSMIT_STOP_ENABLE 0x00000002U
|
||||
#define EMAC_LL_INTR_TRANSMIT_BUFF_UNAVAILABLE_ENABLE 0x00000004U
|
||||
#define EMAC_LL_INTR_TRANSMIT_TIMEOUT_ENABLE 0x00000008U
|
||||
#define EMAC_LL_INTR_OVERFLOW_ENABLE 0x00000010U
|
||||
#define EMAC_LL_INTR_UNDERFLOW_ENABLE 0x00000020U
|
||||
#define EMAC_LL_INTR_RECEIVE_ENABLE 0x00000040U
|
||||
#define EMAC_LL_INTR_REVEIVE_BUFF_UNAVAILABLE_ENABLE 0x00000080U
|
||||
#define EMAC_LL_INTR_RECEIVE_STOP_ENABLE 0x00000100U
|
||||
#define EMAC_LL_INTR_RECEIVE_TIMEOUT_ENABLE 0x00000200U
|
||||
#define EMAC_LL_INTR_TRANSMIT_FIRST_BYTE_ENABLE 0x00000400U
|
||||
#define EMAC_LL_INTR_FATAL_BUS_ERR_ENABLE 0x00002000U
|
||||
#define EMAC_LL_INTR_RECEIVE_FIRST_BYTE_ENABLE 0x00004000U
|
||||
#define EMAC_LL_INTR_ABNORMAL_SUMMARY_ENABLE 0x00008000U
|
||||
#define EMAC_LL_INTR_NORMAL_SUMMARY_ENABLE 0x00010000U
|
||||
|
||||
/* Enable needed interrupts (recv/recv_buf_unavailabal/normal must be enabled to make eth work) */
|
||||
#define EMAC_LL_CONFIG_ENABLE_INTR_MASK (EMAC_LL_INTR_RECEIVE_ENABLE | EMAC_LL_INTR_NORMAL_SUMMARY_ENABLE)
|
||||
|
||||
/************** Start of mac regs operation ********************/
|
||||
/* emacgmiiaddr */
|
||||
static inline void emac_ll_set_csr_clock_division(emac_mac_dev_t *mac_regs, uint32_t div_mode)
|
||||
{
|
||||
mac_regs->emacgmiiaddr.miicsrclk = div_mode;
|
||||
}
|
||||
|
||||
static inline bool emac_ll_is_mii_busy(emac_mac_dev_t *mac_regs)
|
||||
{
|
||||
return mac_regs->emacgmiiaddr.miibusy ? true : false;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_phy_addr(emac_mac_dev_t *mac_regs, uint32_t addr)
|
||||
{
|
||||
mac_regs->emacgmiiaddr.miidev = addr;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_phy_reg(emac_mac_dev_t *mac_regs, uint32_t reg)
|
||||
{
|
||||
mac_regs->emacgmiiaddr.miireg = reg;
|
||||
}
|
||||
|
||||
static inline void emac_ll_write_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->emacgmiiaddr.miiwrite = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_busy(emac_mac_dev_t *mac_regs, bool busy)
|
||||
{
|
||||
mac_regs->emacgmiiaddr.miibusy = busy ? 1 : 0;
|
||||
}
|
||||
|
||||
/* gmacconfig */
|
||||
static inline void emac_ll_watchdog_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.watchdog = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_jabber_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.jabber = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_inter_frame_gap(emac_mac_dev_t *mac_regs, uint32_t gap)
|
||||
{
|
||||
mac_regs->gmacconfig.interframegap = gap;
|
||||
}
|
||||
|
||||
static inline void emac_ll_carrier_sense_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.disablecrs = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_port_speed(emac_mac_dev_t *mac_regs, eth_speed_t speed)
|
||||
{
|
||||
if (speed == ETH_SPEED_10M || speed == ETH_SPEED_100M) {
|
||||
mac_regs->gmacconfig.mii = 1; // 10_100MBPS
|
||||
mac_regs->gmacconfig.fespeed = speed;
|
||||
} else {
|
||||
mac_regs->gmacconfig.mii = 0; // 1000MBPS
|
||||
}
|
||||
}
|
||||
|
||||
static inline void emac_ll_recv_own_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.rxown = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_loopback_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.loopback = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_duplex(emac_mac_dev_t *mac_regs, eth_duplex_t duplex)
|
||||
{
|
||||
mac_regs->gmacconfig.duplex = duplex;
|
||||
}
|
||||
|
||||
static inline void emac_ll_checksum_offload_mode(emac_mac_dev_t *mac_regs, eth_checksum_t mode)
|
||||
{
|
||||
mac_regs->gmacconfig.rxipcoffload = mode;
|
||||
}
|
||||
|
||||
static inline void emac_ll_retry_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.retry = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_auto_pad_crc_strip_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.padcrcstrip = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_back_off_limit(emac_mac_dev_t *mac_regs, uint32_t limit)
|
||||
{
|
||||
mac_regs->gmacconfig.backofflimit = limit;
|
||||
}
|
||||
|
||||
static inline void emac_ll_deferral_check_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.padcrcstrip = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_preamble_length(emac_mac_dev_t *mac_regs, uint32_t len)
|
||||
{
|
||||
mac_regs->gmacconfig.pltf = len;
|
||||
}
|
||||
|
||||
static inline void emac_ll_transmit_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.tx = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_receive_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacconfig.rx = enable;
|
||||
}
|
||||
|
||||
/* gmacff */
|
||||
static inline void emac_ll_receive_all_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacff.receive_all = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_src_addr_filter(emac_mac_dev_t *mac_regs, uint32_t filter)
|
||||
{
|
||||
mac_regs->gmacff.safe = filter;
|
||||
}
|
||||
|
||||
static inline void emac_ll_sa_inverse_filter_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacff.saif = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_pass_ctrl_frame_mode(emac_mac_dev_t *mac_regs, uint32_t mode)
|
||||
{
|
||||
mac_regs->gmacff.pcf = mode;
|
||||
}
|
||||
|
||||
static inline void emac_ll_broadcast_frame_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacff.dbf = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_pass_all_multicast_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacff.pam = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_da_inverse_filter_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacff.daif = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_promiscuous_mode_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacff.pmode = enable;
|
||||
}
|
||||
|
||||
/* gmacfc */
|
||||
static inline void emac_ll_set_pause_time(emac_mac_dev_t *mac_regs, uint32_t time)
|
||||
{
|
||||
mac_regs->gmacfc.pause_time = time;
|
||||
}
|
||||
|
||||
static inline void emac_ll_zero_quanta_pause_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacfc.dzpq = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_pause_low_threshold(emac_mac_dev_t *mac_regs, uint32_t threshold)
|
||||
{
|
||||
mac_regs->gmacfc.plt = threshold;
|
||||
}
|
||||
|
||||
static inline void emac_ll_unicast_pause_frame_detect_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacfc.upfd = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_receive_flow_ctrl_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacfc.rfce = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_transmit_flow_ctrl_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->gmacfc.tfce = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_clear(emac_mac_dev_t *mac_regs)
|
||||
{
|
||||
mac_regs->gmacfc.val = 0;
|
||||
}
|
||||
|
||||
/* emacmiidata */
|
||||
static inline void emac_ll_set_phy_data(emac_mac_dev_t *mac_regs, uint32_t data)
|
||||
{
|
||||
mac_regs->emacmiidata.mii_data = data;
|
||||
}
|
||||
|
||||
static inline uint32_t emac_ll_get_phy_data(emac_mac_dev_t *mac_regs)
|
||||
{
|
||||
return mac_regs->emacmiidata.mii_data;
|
||||
}
|
||||
|
||||
/* emacaddr0 */
|
||||
static inline void emac_ll_set_addr(emac_mac_dev_t *mac_regs, const uint8_t *addr)
|
||||
{
|
||||
mac_regs->emacaddr0high.address0_hi = (addr[5] << 8) | addr[4];
|
||||
mac_regs->emacaddr0low = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | (addr[0]);
|
||||
}
|
||||
/*************** End of mac regs operation *********************/
|
||||
|
||||
|
||||
|
||||
/************** Start of dma regs operation ********************/
|
||||
/* dmabusmode */
|
||||
static inline void emac_ll_reset(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
dma_regs->dmabusmode.sw_rst = 1;
|
||||
}
|
||||
|
||||
static inline bool emac_ll_is_reset_done(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
return dma_regs->dmabusmode.sw_rst ? false : true;
|
||||
}
|
||||
|
||||
/* dmarxbaseaddr / dmatxbaseaddr */
|
||||
static inline void emac_ll_set_rx_desc_addr(emac_dma_dev_t *dma_regs, uint32_t addr)
|
||||
{
|
||||
dma_regs->dmarxbaseaddr = addr;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_tx_desc_addr(emac_dma_dev_t *dma_regs, uint32_t addr)
|
||||
{
|
||||
dma_regs->dmatxbaseaddr = addr;
|
||||
}
|
||||
|
||||
/* dmaoperation_mode */
|
||||
static inline void emac_ll_drop_tcp_err_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.dis_drop_tcpip_err_fram = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_recv_store_forward_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.rx_store_forward = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_flush_recv_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.dis_flush_recv_frames = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_trans_store_forward_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.tx_str_fwd = !enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_flush_trans_fifo_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.flush_tx_fifo = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_transmit_threshold(emac_dma_dev_t *dma_regs, uint32_t threshold)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.tx_thresh_ctrl = threshold;
|
||||
}
|
||||
|
||||
static inline void emac_ll_start_stop_dma_transmit(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.start_stop_transmission_command = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_forward_err_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.fwd_err_frame = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_forward_undersized_good_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.fwd_under_gf = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_recv_threshold(emac_dma_dev_t *dma_regs, uint32_t threshold)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.rx_thresh_ctrl = threshold;
|
||||
}
|
||||
|
||||
static inline void emac_ll_opt_second_frame_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.opt_second_frame = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_start_stop_dma_receive(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmaoperation_mode.start_stop_rx = enable;
|
||||
}
|
||||
|
||||
/* dmabusmode */
|
||||
static inline void emac_ll_mixed_burst_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmabusmode.dmamixedburst = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_addr_align_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmabusmode.dmaaddralibea = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_use_separate_pbl_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmabusmode.use_sep_pbl = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_rx_dma_pbl(emac_dma_dev_t *dma_regs, uint32_t pbl)
|
||||
{
|
||||
dma_regs->dmabusmode.rx_dma_pbl = pbl;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_prog_burst_len(emac_dma_dev_t *dma_regs, uint32_t len)
|
||||
{
|
||||
dma_regs->dmabusmode.prog_burst_len = len;
|
||||
}
|
||||
|
||||
static inline void emac_ll_enhance_desc_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmabusmode.alt_desc_size = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_desc_skip_len(emac_dma_dev_t *dma_regs, uint32_t len)
|
||||
{
|
||||
dma_regs->dmabusmode.desc_skip_len = len;
|
||||
}
|
||||
|
||||
static inline void emac_ll_fixed_arbitration_enable(emac_dma_dev_t *dma_regs, bool enable)
|
||||
{
|
||||
dma_regs->dmabusmode.dma_arb_sch = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_set_priority_ratio(emac_dma_dev_t *dma_regs, uint32_t ratio)
|
||||
{
|
||||
dma_regs->dmabusmode.pri_ratio = ratio;
|
||||
}
|
||||
|
||||
/* dmain_en */
|
||||
static inline void emac_ll_enable_all_intr(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
dma_regs->dmain_en.val = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
static inline void emac_ll_disable_all_intr(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
dma_regs->dmain_en.val = 0x00000000;
|
||||
}
|
||||
|
||||
static inline void emac_ll_enable_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t mask)
|
||||
{
|
||||
dma_regs->dmain_en.val |= mask;
|
||||
}
|
||||
|
||||
static inline void emac_ll_disable_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t mask)
|
||||
{
|
||||
dma_regs->dmain_en.val &= ~mask;
|
||||
}
|
||||
|
||||
static inline uint32_t emac_ll_get_intr_enable_status(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
return dma_regs->dmain_en.val;
|
||||
}
|
||||
|
||||
/* dmastatus */
|
||||
__attribute__((always_inline)) static inline uint32_t emac_ll_get_intr_status(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
return dma_regs->dmastatus.val;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline void emac_ll_clear_corresponding_intr(emac_dma_dev_t *dma_regs, uint32_t bits)
|
||||
{
|
||||
dma_regs->dmastatus.val = bits;
|
||||
}
|
||||
|
||||
__attribute__((always_inline)) static inline void emac_ll_clear_all_pending_intr(emac_dma_dev_t *dma_regs)
|
||||
{
|
||||
dma_regs->dmastatus.val = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
|
||||
/* dmatxpolldemand / dmarxpolldemand */
|
||||
static inline void emac_ll_transmit_poll_demand(emac_dma_dev_t *dma_regs, uint32_t val)
|
||||
{
|
||||
dma_regs->dmatxpolldemand = val;
|
||||
}
|
||||
static inline void emac_ll_receive_poll_demand(emac_dma_dev_t *dma_regs, uint32_t val)
|
||||
{
|
||||
dma_regs->dmarxpolldemand = val;
|
||||
}
|
||||
|
||||
/*************** End of dma regs operation *********************/
|
||||
|
||||
|
||||
|
||||
/************** Start of ext regs operation ********************/
|
||||
static inline void emac_ll_clock_enable_mii(emac_ext_dev_t *ext_regs)
|
||||
{
|
||||
/* 0 for mii mode */
|
||||
ext_regs->ex_phyinf_conf.phy_intf_sel = 0;
|
||||
ext_regs->ex_clk_ctrl.mii_clk_rx_en = 1;
|
||||
ext_regs->ex_clk_ctrl.mii_clk_tx_en = 1;
|
||||
}
|
||||
|
||||
static inline void emac_ll_clock_enable_rmii_input(emac_ext_dev_t *ext_regs)
|
||||
{
|
||||
/* 4 for rmii mode */
|
||||
ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
|
||||
/* ref clk for phy is input in rmii mode, the clk can be offered by mac layer or external crystal.
|
||||
config pin as output to generate ref clk by esp32 mac layer or input to obtain the clock from external crystal */
|
||||
ext_regs->ex_clk_ctrl.ext_en = 1;
|
||||
ext_regs->ex_clk_ctrl.int_en = 0;
|
||||
ext_regs->ex_oscclk_conf.clk_sel = 1;
|
||||
}
|
||||
|
||||
static inline void emac_ll_clock_enable_rmii_output(emac_ext_dev_t *ext_regs)
|
||||
{
|
||||
/* 4 for rmii mode */
|
||||
ext_regs->ex_phyinf_conf.phy_intf_sel = 4;
|
||||
/* ref clk for phy is input in rmii mode, the clk can be offered by mac layer or external crystal.
|
||||
config pin as output to generate ref clk by esp32 mac layer or input to obtain the clock from external crystal */
|
||||
ext_regs->ex_clk_ctrl.ext_en = 0;
|
||||
ext_regs->ex_clk_ctrl.int_en = 1;
|
||||
ext_regs->ex_oscclk_conf.clk_sel = 0;
|
||||
ext_regs->ex_clkout_conf.div_num = 0;
|
||||
ext_regs->ex_clkout_conf.h_div_num = 0;
|
||||
}
|
||||
|
||||
|
||||
static inline void emac_ll_pause_frame_enable(emac_ext_dev_t *ext_regs, bool enable)
|
||||
{
|
||||
ext_regs->ex_phyinf_conf.sbd_flowctrl = enable;
|
||||
}
|
||||
/*************** End of ext regs operation *********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@ -21,169 +21,11 @@ extern "C" {
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "esp_err.h"
|
||||
#include "hal/eth_types.h"
|
||||
#include "soc/emac_dma_struct.h"
|
||||
#include "soc/emac_mac_struct.h"
|
||||
#include "soc/emac_ext_struct.h"
|
||||
|
||||
#define EMAC_MEDIA_INTERFACE_MII (0)
|
||||
#define EMAC_MEDIA_INTERFACE_RMII (1)
|
||||
|
||||
#define EMAC_WATCHDOG_ENABLE (0)
|
||||
#define EMAC_WATCHDOG_DISABLE (1)
|
||||
|
||||
#define EMAC_JABBER_ENABLE (0)
|
||||
#define EMAC_JABBER_DISABLE (1)
|
||||
|
||||
#define EMAC_INTERFRAME_GAP_96BIT (0)
|
||||
#define EMAC_INTERFRAME_GAP_88BIT (1)
|
||||
#define EMAC_INTERFRAME_GAP_80BIT (2)
|
||||
#define EMAC_INTERFRAME_GAP_72BIT (3)
|
||||
#define EMAC_INTERFRAME_GAP_64BIT (4)
|
||||
#define EMAC_INTERFRAME_GAP_56BIT (5)
|
||||
#define EMAC_INTERFRAME_GAP_48BIT (6)
|
||||
#define EMAC_INTERFRAME_GAP_40BIT (7)
|
||||
|
||||
#define EMAC_CARRIERSENSE_ENABLE (0)
|
||||
#define EMAC_CARRIERSENSE_DISABLE (1)
|
||||
|
||||
#define EMAC_PORT_1000MBPS (0)
|
||||
#define EMAC_PORT_10_100MBPS (1)
|
||||
|
||||
#define EMAC_SPEED_10M (0)
|
||||
#define EMAC_SPEED_100M (1)
|
||||
|
||||
#define EMAC_RECEIVE_OWN_ENABLE (0)
|
||||
#define EMAC_RECEIVE_OWN_DISABLE (1)
|
||||
|
||||
#define EMAC_LOOPBACK_DISABLE (0)
|
||||
#define EMAC_LOOPBACK_ENABLE (1)
|
||||
|
||||
#define EMAC_DUPLEX_HALF (0)
|
||||
#define EMAC_DUPLEX_FULL (1)
|
||||
|
||||
#define EMAC_CHECKSUM_SW (0)
|
||||
#define EMAC_CHECKSUM_HW (1)
|
||||
|
||||
#define EMAC_RETRY_TRANSMISSION_ENABLE (0)
|
||||
#define EMAC_RETRY_TRANSMISSION_DISABLE (1)
|
||||
|
||||
#define EMAC_AUTO_PAD_CRC_STRIP_DISABLE (0)
|
||||
#define EMAC_AUTO_PAD_CRC_STRIP_ENABLE (1)
|
||||
|
||||
#define EMAC_BACKOFF_LIMIT_10 (0)
|
||||
#define EMAC_BACKOFF_LIMIT_8 (1)
|
||||
#define EMAC_BACKOFF_LIMIT_4 (2)
|
||||
#define EMAC_BACKOFF_LIMIT_1 (3)
|
||||
|
||||
#define EMAC_DEFERRAL_CHECK_DISABLE (0)
|
||||
#define EMAC_DEFERRAL_CHECK_ENABLE (1)
|
||||
|
||||
#define EMAC_PREAMBLE_LENGTH_7 (0)
|
||||
#define EMAC_PREAMBLE_LENGTH_5 (1)
|
||||
#define EMAC_PREAMBLE_LENGTH_3 (2)
|
||||
|
||||
#define EMAC_RECEIVE_ALL_DISABLE (0)
|
||||
#define EMAC_RECEIVE_ALL_ENABLE (1)
|
||||
|
||||
#define EMAC_SOURCE_ADDR_FILTER_DISABLE (0)
|
||||
#define EMAC_SOURCE_ADDR_FILTER_NORMAL (2)
|
||||
#define EMAC_SOURCE_ADDR_FILTER_INVERSE (3)
|
||||
|
||||
#define EMAC_CONTROL_FRAME_BLOCKALL (0)
|
||||
#define EMAC_CONTROL_FRAME_FORWARDALL_PAUSE (1)
|
||||
#define EMAC_CONTROL_FRAME_FORWARDALL (2)
|
||||
#define EMAC_CONTROL_FRAME_FORWARDFILT (3)
|
||||
|
||||
#define EMAC_RECEPT_BROADCAST_ENABLE (0)
|
||||
#define EMAC_RECEPT_BROADCAST_DISABLE (1)
|
||||
|
||||
#define EMAC_DEST_ADDR_FILTER_NORMAL (0)
|
||||
#define EMAC_DEST_ADDR_FILTER_INVERSE (1)
|
||||
|
||||
#define EMAC_PROMISCUOUS_DISABLE (0)
|
||||
#define EMAC_PROMISCUOUS_ENABLE (1)
|
||||
|
||||
#define EMAC_PAUSE_TIME 0x1648
|
||||
|
||||
#define EMAC_ZERO_QUANTA_PAUSE_ENABLE (0)
|
||||
#define EMAC_ZERO_QUANTA_PAUSE_DISABLE (1)
|
||||
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_4 (0)
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_28 (1)
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_144 (2)
|
||||
#define EMAC_PAUSE_LOW_THRESHOLD_MINUS_256
|
||||
|
||||
#define EMAC_UNICAST_PAUSE_DETECT_DISABLE (0)
|
||||
#define EMAC_UNICAST_PAUSE_DETECT_ENABLE (1)
|
||||
|
||||
#define EMAC_RECEIVE_FLOW_CONTROL_DISABLE (0)
|
||||
#define EMAC_RECEIVE_FLOW_CONTROL_ENABLE (1)
|
||||
|
||||
#define EMAC_TRANSMIT_FLOW_CONTROL_DISABLE (0)
|
||||
#define EMAC_TRANSMIT_FLOW_CONTROL_ENABLE (1)
|
||||
|
||||
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_ENABLE (0)
|
||||
#define EMAC_DROP_TCPIP_CHECKSUM_ERROR_DISABLE (1)
|
||||
|
||||
#define EMAC_RECEIVE_STORE_FORWARD_DISABLE (0)
|
||||
#define EMAC_RECEIVE_STORE_FORWARD_ENABLE (1)
|
||||
|
||||
#define EMAC_FLUSH_RECEIVED_FRAME_ENABLE (0)
|
||||
#define EMAC_FLUSH_RECEIVED_FRAME_DISABLE (1)
|
||||
|
||||
#define EMAC_TRANSMIT_STORE_FORWARD_DISABLE (0)
|
||||
#define EMAC_TRANSMIT_STORE_FORWARD_ENABLE (1)
|
||||
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_64 (0)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_128 (1)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_192 (2)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_256 (3)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_40 (4)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_32 (5)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_24 (6)
|
||||
#define EMAC_TRANSMIT_THRESHOLD_CONTROL_16 (7)
|
||||
|
||||
#define EMAC_FORWARD_ERROR_FRAME_DISABLE (0)
|
||||
#define EMAC_FORWARD_ERROR_FRAME_ENABLE (1)
|
||||
|
||||
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_DISABLE (0)
|
||||
#define EMAC_FORWARD_UNDERSIZED_GOOD_FRAME_ENABLE (1)
|
||||
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_64 (0)
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_32 (1)
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_96 (2)
|
||||
#define EMAC_RECEIVE_THRESHOLD_CONTROL_128 (3)
|
||||
|
||||
#define EMAC_OPERATE_SECOND_FRAME_DISABLE (0)
|
||||
#define EMAC_OPERATE_SECOND_FRAME_ENABLE (1)
|
||||
|
||||
#define EMAC_MIXED_BURST_DISABLE (0)
|
||||
#define EMAC_MIXED_BURST_ENABLE (1)
|
||||
|
||||
#define EMAC_ADDR_ALIGN_BEATS_DISABLE (0)
|
||||
#define EMAC_ADDR_ALIGN_BEATS_ENABLE (1)
|
||||
|
||||
#define EMAC_UNUSE_SEPARATE_PBL (0)
|
||||
#define EMAC_USE_SEPARATE_PBL (1)
|
||||
|
||||
#define EMAC_DMA_BURST_LENGTH_1BEAT (1)
|
||||
#define EMAC_DMA_BURST_LENGTH_2BEAT (2)
|
||||
#define EMAC_DMA_BURST_LENGTH_4BEAT (4)
|
||||
#define EMAC_DMA_BURST_LENGTH_8BEAT (8)
|
||||
#define EMAC_DMA_BURST_LENGTH_16BEAT (16)
|
||||
#define EMAC_DMA_BURST_LENGTH_32BEAT (32)
|
||||
|
||||
#define EMAC_ENHANCED_DESCRIPTOR_DISABLE (0)
|
||||
#define EMAC_ENHANCED_DESCRIPTOR_ENABLE (1)
|
||||
|
||||
#define EMAC_DMA_ARBITRATION_SCHEME_ROUNDROBIN (0)
|
||||
#define EMAC_DMA_ARBITRATION_SCHEME_FIXEDPRIO (1)
|
||||
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_1_1 (0)
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_2_1 (1)
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_3_1 (2)
|
||||
#define EMAC_DMA_ARBITRATION_ROUNDROBIN_RXTX_4_1 (3)
|
||||
|
||||
/**
|
||||
* @brief Ethernet DMA TX Descriptor
|
||||
*
|
||||
@ -315,20 +157,6 @@ typedef struct {
|
||||
uint32_t TimeStampLow; /*!< Receive frame timestamp low */
|
||||
uint32_t TimeStampHigh; /*!< Receive frame timestamp high */
|
||||
} eth_dma_rx_descriptor_t;
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_SYNC 0x00000100U /* SYNC message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_FOLLOWUP 0x00000200U /* FollowUp message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYREQ 0x00000300U /* DelayReq message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_DELAYRESP 0x00000400U /* DelayResp message (all clock types) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYREQ_ANNOUNCE 0x00000500U /* PdelayReq message (peer-to-peer transparent clock) or Announce message (Ordinary or Boundary clock) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESP_MANAG 0x00000600U /* PdelayResp message (peer-to-peer transparent clock) or Management message (Ordinary or Boundary clock) */
|
||||
#define EMAC_DMAPTPRXDESC_PTPMT_PDELAYRESPFOLLOWUP_SIGNAL 0x00000700U /* PdelayRespFollowUp message (peer-to-peer transparent clock) or Signaling message (Ordinary or Boundary clock) */
|
||||
|
||||
#define EMAC_DMAPTPRXDESC_IPPT_UDP 0x00000001U /* UDP payload encapsulated in the IP datagram */
|
||||
#define EMAC_DMAPTPRXDESC_IPPT_TCP 0x00000002U /* TCP payload encapsulated in the IP datagram */
|
||||
#define EMAC_DMAPTPRXDESC_IPPT_ICMP 0x00000003U /* ICMP payload encapsulated in the IP datagram */
|
||||
|
||||
#define EMAC_DMADESC_OWNER_CPU (0)
|
||||
#define EMAC_DMADESC_OWNER_DMA (1)
|
||||
|
||||
_Static_assert(sizeof(eth_dma_rx_descriptor_t) == 32, "eth_dma_rx_descriptor_t should occupy 32 bytes in memory");
|
||||
|
||||
@ -341,20 +169,31 @@ typedef struct {
|
||||
void *descriptors;
|
||||
eth_dma_rx_descriptor_t *rx_desc;
|
||||
eth_dma_tx_descriptor_t *tx_desc;
|
||||
|
||||
} emac_hal_context_t;
|
||||
|
||||
void emac_hal_init(emac_hal_context_t *hal, void *descriptors,
|
||||
uint8_t **rx_buf, uint8_t **tx_buf);
|
||||
|
||||
void emac_hal_reset_desc_chain(emac_hal_context_t *hal);
|
||||
void emac_hal_iomux_init_mii(void);
|
||||
|
||||
void emac_hal_lowlevel_init(emac_hal_context_t *hal);
|
||||
void emac_hal_iomux_init_rmii(void);
|
||||
|
||||
void emac_hal_iomux_rmii_clk_input(void);
|
||||
|
||||
void emac_hal_iomux_rmii_clk_ouput(int num);
|
||||
|
||||
void emac_hal_iomux_init_tx_er(void);
|
||||
|
||||
void emac_hal_iomux_init_rx_er(void);
|
||||
|
||||
void emac_hal_reset_desc_chain(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_reset(emac_hal_context_t *hal);
|
||||
|
||||
bool emac_hal_is_reset_done(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal);
|
||||
void emac_hal_set_csr_clock_range(emac_hal_context_t *hal, int freq);
|
||||
|
||||
void emac_hal_init_mac_default(emac_hal_context_t *hal);
|
||||
|
||||
@ -362,7 +201,7 @@ void emac_hal_init_dma_default(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_set_speed(emac_hal_context_t *hal, uint32_t speed);
|
||||
|
||||
void emac_hal_set_duplex(emac_hal_context_t *hal, uint32_t duplex);
|
||||
void emac_hal_set_duplex(emac_hal_context_t *hal, eth_duplex_t duplex);
|
||||
|
||||
void emac_hal_set_promiscuous(emac_hal_context_t *hal, bool enable);
|
||||
|
||||
@ -393,17 +232,13 @@ uint32_t emac_hal_receive_frame(emac_hal_context_t *hal, uint8_t *buf, uint32_t
|
||||
|
||||
void emac_hal_enable_flow_ctrl(emac_hal_context_t *hal, bool enable);
|
||||
|
||||
void emac_hal_isr(void *arg);
|
||||
uint32_t emac_hal_get_intr_enable_status(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_tx_complete_cb(void *arg);
|
||||
uint32_t emac_hal_get_intr_status(emac_hal_context_t *hal);
|
||||
|
||||
void emac_hal_tx_unavail_cb (void *arg);
|
||||
void emac_hal_clear_corresponding_intr(emac_hal_context_t *hal, uint32_t bits);
|
||||
|
||||
void emac_hal_rx_complete_cb (void *arg);
|
||||
|
||||
void emac_hal_rx_early_cb(void *arg);
|
||||
|
||||
void emac_hal_rx_unavail_cb(void *arg);
|
||||
void emac_hal_clear_all_intr(emac_hal_context_t *hal);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
65
components/hal/include/hal/eth_types.h
Normal file
65
components/hal/include/hal/eth_types.h
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @brief Ethernet frame CRC length
|
||||
*
|
||||
*/
|
||||
#define ETH_CRC_LEN (4)
|
||||
|
||||
/**
|
||||
* @brief Ethernet interface
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
EMAC_INTERFACE_MII, /*!< Media Independent Interface */
|
||||
EMAC_INTERFACE_RMII /*!< Reduced Media Independent Interface */
|
||||
} eth_data_interface_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet link status
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_LINK_UP, /*!< Ethernet link is up */
|
||||
ETH_LINK_DOWN /*!< Ethernet link is down */
|
||||
} eth_link_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet speed
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_SPEED_10M, /*!< Ethernet speed is 10Mbps */
|
||||
ETH_SPEED_100M, /*!< Ethernet speed is 100Mbps */
|
||||
ETH_SPEED_MAX /*!< Max speed mode (for checking purpose) */
|
||||
} eth_speed_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet duplex mode
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_DUPLEX_HALF, /*!< Ethernet is in half duplex */
|
||||
ETH_DUPLEX_FULL, /*!< Ethernet is in full duplex */
|
||||
} eth_duplex_t;
|
||||
|
||||
/**
|
||||
* @brief Ethernet Checksum
|
||||
*/
|
||||
typedef enum {
|
||||
ETH_CHECKSUM_SW, /*!< Ethernet checksum calculate by software */
|
||||
ETH_CHECKSUM_HW /*!< Ethernet checksum calculate by hardware */
|
||||
} eth_checksum_t;
|
@ -67,6 +67,7 @@ INPUT = \
|
||||
$(IDF_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_sensor_model_api.h \
|
||||
$(IDF_PATH)/components/bt/esp_ble_mesh/api/models/include/esp_ble_mesh_time_scene_model_api.h \
|
||||
$(IDF_PATH)/components/bt/esp_ble_mesh/api/esp_ble_mesh_defs.h \
|
||||
$(IDF_PATH)/components/hal/include/hal/eth_types.h \
|
||||
$(IDF_PATH)/components/esp_eth/include/esp_eth.h \
|
||||
$(IDF_PATH)/components/esp_eth/include/esp_eth_com.h \
|
||||
$(IDF_PATH)/components/esp_eth/include/esp_eth_mac.h \
|
||||
|
Loading…
x
Reference in New Issue
Block a user