From fe354f1c5003d6aa0b2261f5518d086b6d14c447 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Fri, 7 May 2021 17:38:36 +0800 Subject: [PATCH] hal/emac_hal: refactord emac_hal --- components/esp_eth/include/esp_eth_com.h | 34 +- components/esp_eth/src/esp_eth_mac_esp.c | 194 ++--- components/hal/CMakeLists.txt | 2 +- components/hal/component.mk | 4 +- components/hal/emac_hal.c | 514 +++++++++++++ components/hal/esp32/emac_hal.c | 687 ------------------ components/hal/esp32/include/hal/emac_ll.h | 596 +++++++++++++++ .../hal/emac.h => include/hal/emac_hal.h} | 207 +----- components/hal/include/hal/eth_types.h | 65 ++ docs/doxygen/Doxyfile_common | 1 + 10 files changed, 1307 insertions(+), 997 deletions(-) create mode 100644 components/hal/emac_hal.c delete mode 100644 components/hal/esp32/emac_hal.c create mode 100644 components/hal/esp32/include/hal/emac_ll.h rename components/hal/{esp32/include/hal/emac.h => include/hal/emac_hal.h} (64%) create mode 100644 components/hal/include/hal/eth_types.h diff --git a/components/esp_eth/include/esp_eth_com.h b/components/esp_eth/include/esp_eth_com.h index b8d831cf15..46409ed710 100644 --- a/components/esp_eth/include/esp_eth_com.h +++ b/components/esp_eth/include/esp_eth_com.h @@ -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 * diff --git a/components/esp_eth/src/esp_eth_mac_esp.c b/components/esp_eth/src/esp_eth_mac_esp.c index 6ce8d541c8..6f49cbaebb 100644 --- a/components/esp_eth/src/esp_eth_mac_esp.c +++ b/components/esp_eth/src/esp_eth_mac_esp.c @@ -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; - } -} diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index 6196268bd0..bae4fef882 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -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() diff --git a/components/hal/component.mk b/components/hal/component.mk index 90709a82b4..81a21c9e39 100644 --- a/components/hal/component.mk +++ b/components/hal/component.mk @@ -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 diff --git a/components/hal/emac_hal.c b/components/hal/emac_hal.c new file mode 100644 index 0000000000..bd202edb34 --- /dev/null +++ b/components/hal/emac_hal.c @@ -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 +#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; +} diff --git a/components/hal/esp32/emac_hal.c b/components/hal/esp32/emac_hal.c deleted file mode 100644 index 5ba3c4aec9..0000000000 --- a/components/hal/esp32/emac_hal.c +++ /dev/null @@ -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 -#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; -} diff --git a/components/hal/esp32/include/hal/emac_ll.h b/components/hal/esp32/include/hal/emac_ll.h new file mode 100644 index 0000000000..36477e36f5 --- /dev/null +++ b/components/hal/esp32/include/hal/emac_ll.h @@ -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 +#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 diff --git a/components/hal/esp32/include/hal/emac.h b/components/hal/include/hal/emac_hal.h similarity index 64% rename from components/hal/esp32/include/hal/emac.h rename to components/hal/include/hal/emac_hal.h index ec0c1ab3b9..f661e58985 100644 --- a/components/hal/esp32/include/hal/emac.h +++ b/components/hal/include/hal/emac_hal.h @@ -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 #include #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 } diff --git a/components/hal/include/hal/eth_types.h b/components/hal/include/hal/eth_types.h new file mode 100644 index 0000000000..724948453d --- /dev/null +++ b/components/hal/include/hal/eth_types.h @@ -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; diff --git a/docs/doxygen/Doxyfile_common b/docs/doxygen/Doxyfile_common index 004c48370e..6ab8e50af6 100644 --- a/docs/doxygen/Doxyfile_common +++ b/docs/doxygen/Doxyfile_common @@ -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 \