mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-23 01:05:14 +00:00
Merge branch 'feat/p4_emac_sleep' into 'master'
feat(esp_eth): added EMAC sleep retention for ESP32P4 Closes IDF-9919 See merge request espressif/esp-idf!40385
This commit is contained in:
@@ -198,7 +198,8 @@ typedef enum {
|
||||
ETH_MAC_ESP_CMD_ADJ_PTP_TIME, /*!< Adjust base PTP time frequency increment by PPS */
|
||||
ETH_MAC_ESP_CMD_S_TARGET_TIME, /*!< Set Target Time at which interrupt is invoked when PTP time exceeds this value*/
|
||||
ETH_MAC_ESP_CMD_S_TARGET_CB, /*!< Set pointer to a callback function invoked when PTP time exceeds Target Time */
|
||||
ETH_MAC_ESP_CMD_ENABLE_TS4ALL /*!< Enable timestamp for all received frames */
|
||||
ETH_MAC_ESP_CMD_ENABLE_TS4ALL, /*!< Enable timestamp for all received frames */
|
||||
ETH_MAC_ESP_CMD_DUMP_REGS, /*!< Dump EMAC registers */
|
||||
} eth_mac_esp_io_cmd_t;
|
||||
|
||||
#ifdef SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
|
@@ -3,12 +3,14 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/cdefs.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/sleep_retention.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
@@ -28,6 +30,7 @@
|
||||
#include "freertos/semphr.h"
|
||||
#include "hal/emac_hal.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/emac_periph.h"
|
||||
#include "clk_ctrl_os.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_rom_sys.h"
|
||||
@@ -56,6 +59,8 @@ static const char *TAG = "esp.emac";
|
||||
#define EMAC_IF_RCC_ATOMIC()
|
||||
#endif
|
||||
|
||||
#define EMAC_USE_RETENTION_LINK (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_EMAC_SUPPORT_SLEEP_RETENTION)
|
||||
|
||||
typedef struct {
|
||||
esp_eth_mac_t parent;
|
||||
esp_eth_mediator_t *eth;
|
||||
@@ -68,7 +73,6 @@ typedef struct {
|
||||
uint32_t free_rx_descriptor;
|
||||
uint32_t flow_control_high_water_mark;
|
||||
uint32_t flow_control_low_water_mark;
|
||||
uint8_t addr[ETH_ADDR_LEN];
|
||||
bool flow_ctrl_enabled; // indicates whether the user want to do flow control
|
||||
bool do_flow_ctrl; // indicates whether we need to do software flow control
|
||||
bool use_pll; // Only use (A/M)PLL in EMAC_DATA_INTERFACE_RMII && EMAC_CLK_OUT
|
||||
@@ -92,6 +96,55 @@ static void emac_esp_free_driver_obj(emac_esp32_t *emac);
|
||||
static esp_err_t emac_esp32_start(esp_eth_mac_t *mac);
|
||||
static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac);
|
||||
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
static esp_err_t emac_create_sleep_retention_link_cb(void *arg)
|
||||
{
|
||||
esp_err_t err = sleep_retention_entries_create(emac_reg_retention_info.entry_array,
|
||||
emac_reg_retention_info.array_size,
|
||||
REGDMA_LINK_PRI_EMAC, emac_reg_retention_info.module_id);
|
||||
return err;
|
||||
}
|
||||
|
||||
// TODO rename to emac_esp
|
||||
static esp_err_t emac_create_retention_module(emac_esp32_t *emac)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
sleep_retention_module_t module = emac_reg_retention_info.module_id;
|
||||
if (sleep_retention_is_module_inited(module) && !sleep_retention_is_module_created(module)) {
|
||||
if ((ret = sleep_retention_module_allocate(module)) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "create retention link failed on EMAC, power domain won't be turned off during sleep");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void emac_esp_enable_emac_start_on_wakeup(emac_esp32_t *emac)
|
||||
{
|
||||
void *emac_start_link;
|
||||
for (int i = 0; i < EMAC_REGDMA_LINK_EMAC_START_CNT; i++) {
|
||||
emac_start_link = sleep_retention_find_link_by_id(emac_reg_retention_info.entry_array[EMAC_REGDMA_LINK_EMAC_START_BEGIN + i].config.id);
|
||||
regdma_link_set_skip_flag(emac_start_link, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void emac_esp_disable_emac_start_on_wakeup(emac_esp32_t *emac)
|
||||
{
|
||||
void *emac_start_link;
|
||||
for (int i = 0; i < EMAC_REGDMA_LINK_EMAC_START_CNT; i++) {
|
||||
emac_start_link = sleep_retention_find_link_by_id(emac_reg_retention_info.entry_array[EMAC_REGDMA_LINK_EMAC_START_BEGIN + i].config.id);
|
||||
regdma_link_set_skip_flag(emac_start_link, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void emac_free_retention_module(emac_esp32_t *emac)
|
||||
{
|
||||
sleep_retention_module_t module = emac_reg_retention_info.module_id;
|
||||
if (sleep_retention_is_module_created(module)) {
|
||||
sleep_retention_module_free(module);
|
||||
}
|
||||
}
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
|
||||
static esp_err_t emac_esp32_lock_multi_reg(emac_esp32_t *emac)
|
||||
{
|
||||
return xSemaphoreTake(emac->multi_reg_mutex, pdMS_TO_TICKS(EMAC_MULTI_REG_MUTEX_TIMEOUT_MS)) == pdTRUE ? ESP_OK : ESP_ERR_TIMEOUT;
|
||||
@@ -162,8 +215,7 @@ static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
memcpy(emac->addr, addr, 6);
|
||||
emac_hal_set_address(&emac->hal, emac->addr);
|
||||
emac_hal_set_address(&emac->hal, addr);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
@@ -174,7 +226,7 @@ static esp_err_t emac_esp32_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
|
||||
esp_err_t ret = ESP_OK;
|
||||
ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
memcpy(addr, emac->addr, 6);
|
||||
emac_hal_get_address(&emac->hal, addr);
|
||||
return ESP_OK;
|
||||
err:
|
||||
return ret;
|
||||
@@ -298,6 +350,15 @@ static esp_err_t emac_esp32_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void emac_esp_dump_hal_registers(emac_esp32_t *emac)
|
||||
{
|
||||
ESP_LOG_BUFFER_HEXDUMP("DMA", emac->hal.dma_regs, sizeof(emac_dma_dev_t), ESP_LOG_INFO);
|
||||
ESP_LOG_BUFFER_HEXDUMP("MAC", emac->hal.mac_regs, sizeof(emac_mac_dev_t), ESP_LOG_INFO);
|
||||
#ifdef SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
ESP_LOG_BUFFER_HEXDUMP("PTP", emac->hal.ptp_regs, sizeof(emac_ptp_dev_t), ESP_LOG_INFO);
|
||||
#endif // SOC_EMAC_IEEE1588V2_SUPPORTED
|
||||
}
|
||||
|
||||
esp_err_t emac_esp_custom_ioctl(esp_eth_mac_t *mac, int cmd, void *data)
|
||||
{
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
@@ -389,6 +450,9 @@ esp_err_t emac_esp_custom_ioctl(esp_eth_mac_t *mac, int cmd, void *data)
|
||||
ESP_RETURN_ON_FALSE(data != NULL, ESP_ERR_INVALID_ARG, TAG, "cannot clear DMA tx desc flag with null");
|
||||
emac_esp_dma_clear_tdes0_ctrl_bits(emac->emac_dma_hndl, *(uint32_t *)data);
|
||||
break;
|
||||
case ETH_MAC_ESP_CMD_DUMP_REGS:
|
||||
emac_esp_dump_hal_registers(emac);
|
||||
break;
|
||||
default:
|
||||
ESP_RETURN_ON_ERROR(ESP_ERR_INVALID_ARG, TAG, "unknown io command: %i", cmd);
|
||||
}
|
||||
@@ -561,12 +625,16 @@ static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
|
||||
emac_hal_dma_config_t dma_config = { .dma_burst_len = emac->dma_burst_len };
|
||||
emac_hal_init_dma_default(&emac->hal, &dma_config);
|
||||
/* get emac address from efuse */
|
||||
ESP_GOTO_ON_ERROR(esp_read_mac(emac->addr, ESP_MAC_ETH), err, TAG, "fetch ethernet mac address failed");
|
||||
uint8_t addr[ETH_ADDR_LEN];
|
||||
ESP_GOTO_ON_ERROR(esp_read_mac(addr, ESP_MAC_ETH), err, TAG, "fetch ethernet mac address failed");
|
||||
/* set MAC address to emac register */
|
||||
emac_hal_set_address(&emac->hal, emac->addr);
|
||||
emac_hal_set_address(&emac->hal, addr);
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(emac->pm_lock);
|
||||
#endif
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
emac_create_retention_module(emac);
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
return ESP_OK;
|
||||
|
||||
err:
|
||||
@@ -581,6 +649,9 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
esp_pm_lock_release(emac->pm_lock);
|
||||
#endif
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
emac_free_retention_module(emac);
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
emac_hal_stop(&emac->hal);
|
||||
eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
|
||||
return ESP_OK;
|
||||
@@ -591,6 +662,9 @@ static esp_err_t emac_esp32_start(esp_eth_mac_t *mac)
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
/* reset descriptor chain */
|
||||
emac_esp_dma_reset(emac->emac_dma_hndl);
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
emac_esp_enable_emac_start_on_wakeup(emac);
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
emac_hal_start(&emac->hal);
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -600,6 +674,9 @@ static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac)
|
||||
emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
|
||||
esp_err_t ret = ESP_OK;
|
||||
int32_t to = 0;
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
emac_esp_disable_emac_start_on_wakeup(emac);
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
do {
|
||||
if ((ret = emac_hal_stop(&emac->hal)) == ESP_OK) {
|
||||
break;
|
||||
@@ -689,6 +766,12 @@ static void emac_esp_free_driver_obj(emac_esp32_t *emac)
|
||||
esp_pm_lock_delete(emac->pm_lock);
|
||||
}
|
||||
#endif // CONFIG_PM_ENABLE
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = emac_reg_retention_info.module_id;
|
||||
if (sleep_retention_is_module_inited(module)) {
|
||||
sleep_retention_module_deinit(module);
|
||||
}
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
|
||||
emac_esp_del_dma(emac->emac_dma_hndl);
|
||||
|
||||
@@ -707,13 +790,30 @@ static esp_err_t emac_esp_alloc_driver_obj(const eth_mac_config_t *config, emac_
|
||||
}
|
||||
ESP_GOTO_ON_FALSE(emac, ESP_ERR_NO_MEM, err, TAG, "no mem for esp emac object");
|
||||
|
||||
ESP_GOTO_ON_ERROR(emac_esp_new_dma(NULL, &emac->emac_dma_hndl), err, TAG, "create EMAC DMA object failed");
|
||||
|
||||
/* alloc PM lock */
|
||||
#ifdef CONFIG_PM_ENABLE
|
||||
ESP_GOTO_ON_ERROR(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock), err, TAG, "create pm lock failed");
|
||||
#endif
|
||||
|
||||
#if EMAC_USE_RETENTION_LINK
|
||||
sleep_retention_module_t module = emac_reg_retention_info.module_id;
|
||||
sleep_retention_module_init_param_t init_param = {
|
||||
.cbs = {
|
||||
.create = {
|
||||
.handle = emac_create_sleep_retention_link_cb,
|
||||
.arg = (void *)emac
|
||||
},
|
||||
},
|
||||
.depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM)
|
||||
};
|
||||
if (sleep_retention_module_init(module, &init_param) != ESP_OK) {
|
||||
// even though the sleep retention module init failed, EMAC driver should still work, so just warning here
|
||||
ESP_LOGW(TAG, "init sleep retention failed on EMAC, power domain may be turned off during sleep");
|
||||
}
|
||||
#endif // EMAC_USE_RETENTION_LINK
|
||||
|
||||
ESP_GOTO_ON_ERROR(emac_esp_new_dma(NULL, &emac->emac_dma_hndl), err, TAG, "create EMAC DMA object failed");
|
||||
|
||||
emac->multi_reg_mutex = xSemaphoreCreateMutex();
|
||||
ESP_GOTO_ON_FALSE(emac->multi_reg_mutex, ESP_ERR_NO_MEM, err, TAG, "failed to create multiple register access mutex");
|
||||
|
||||
|
@@ -3,8 +3,9 @@ idf_component_register(SRCS "esp_eth_test_apps.c"
|
||||
"esp_eth_test_esp_emac.c"
|
||||
"esp_eth_test_common.c"
|
||||
"esp_eth_test_main.c"
|
||||
"test_emac_sleep_retention.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client esp_driver_gpio
|
||||
PRIV_REQUIRES unity test_utils esp_eth esp_netif esp_http_client esp_driver_gpio esp_driver_uart
|
||||
EMBED_TXTFILES dl_espressif_com_root_cert.pem
|
||||
WHOLE_ARCHIVE)
|
||||
|
@@ -102,4 +102,9 @@ menu "esp_eth TEST_APPS Configuration"
|
||||
|
||||
endif # TARGET_USE_SPI_ETHERNET
|
||||
|
||||
config TARGET_ETH_PHY_RESET_GPIO
|
||||
int "PHY Reset GPIO number"
|
||||
default 5 if IDF_TARGET_ESP32
|
||||
default 51 if IDF_TARGET_ESP32P4
|
||||
default -1
|
||||
endmenu
|
||||
|
@@ -106,6 +106,7 @@ esp_eth_phy_t *phy_init(eth_phy_config_t *phy_config)
|
||||
{
|
||||
esp_eth_phy_t *phy = NULL;
|
||||
eth_phy_config_t phy_config_default = ETH_PHY_DEFAULT_CONFIG();
|
||||
phy_config_default.reset_gpio_num = CONFIG_TARGET_ETH_PHY_RESET_GPIO;
|
||||
if (phy_config == NULL) {
|
||||
phy_config = &phy_config_default;
|
||||
}
|
||||
|
358
components/esp_eth/test_apps/main/test_emac_sleep_retention.c
Normal file
358
components/esp_eth/test_apps/main/test_emac_sleep_retention.c
Normal file
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "soc/emac_mac_struct.h"
|
||||
#include "unity.h"
|
||||
#include "unity_test_utils.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_eth.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "driver/uart.h"
|
||||
#include "esp_private/sleep_cpu.h"
|
||||
#include "esp_private/esp_sleep_internal.h"
|
||||
#include "esp_private/esp_pmu.h"
|
||||
#include "esp_eth_test_common.h"
|
||||
#include "hal/emac_hal.h"
|
||||
|
||||
#include "lwip/inet.h"
|
||||
#include "ping/ping_sock.h"
|
||||
|
||||
#define ETH_TEST_DEBUG_EN (0) // set to 1 to enable test debug
|
||||
|
||||
#define ETH_SLEEP_DURATION_US (1000000) // 1 second
|
||||
|
||||
// send more pings than Number of DMA transmit buffers to ensure that descriptors are correctly returned back to its owners
|
||||
// and overflow is handled correctly
|
||||
#define ETH_PING_CNT (CONFIG_ETH_DMA_TX_BUFFER_NUM + 5)
|
||||
#define ETH_PING_INTERVAL_MS (100)
|
||||
#define ETH_PING_TIMEOUT_MS (1000)
|
||||
#define ETH_PING_SEM_TIMEOUT_MS (ETH_PING_TIMEOUT_MS * ETH_PING_CNT * 2)
|
||||
|
||||
#define ETH_TEST_ETHERTYPE (0x0666)
|
||||
#define ETH_RECV_TIMEOUT_MS (50)
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
static const char *TAG = "emac_sleep_test";
|
||||
|
||||
static void eth_test_start_sleep(esp_eth_handle_t eth_handle, bool pd_top_down)
|
||||
{
|
||||
esp_sleep_context_t sleep_ctx;
|
||||
esp_sleep_set_sleep_context(&sleep_ctx);
|
||||
|
||||
// Configure sleep
|
||||
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||
if (pd_top_down) {
|
||||
printf("Enable CPU power down\n");
|
||||
TEST_ESP_OK(sleep_cpu_configure(true));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ETH_TEST_DEBUG_EN
|
||||
esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_DUMP_REGS, NULL);
|
||||
#endif
|
||||
|
||||
uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
TEST_ESP_OK(esp_sleep_enable_timer_wakeup(ETH_SLEEP_DURATION_US));
|
||||
ESP_LOGI(TAG, "Entering light sleep for %d us...", ETH_SLEEP_DURATION_US);
|
||||
printf("\n ( -.-)Zzz\n\n");
|
||||
TEST_ESP_OK(esp_light_sleep_start());
|
||||
printf("\n ( o_o)!\n\n");
|
||||
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||
if (pd_top_down) {
|
||||
TEST_ESP_OK(sleep_cpu_configure(false));
|
||||
}
|
||||
#endif
|
||||
ESP_LOGI(TAG, "Woke up from light sleep");
|
||||
|
||||
// Verify sleep happened as expected
|
||||
TEST_ASSERT_EQUAL(0, sleep_ctx.sleep_request_result);
|
||||
|
||||
#if ETH_TEST_DEBUG_EN
|
||||
esp_eth_ioctl(eth_handle, ETH_MAC_ESP_CMD_DUMP_REGS, NULL);
|
||||
#endif
|
||||
|
||||
#if !SOC_PM_TOP_PD_NOT_ALLOWED
|
||||
printf("sleep_ctx.sleep_flags: 0x%" PRIx32 "\n", sleep_ctx.sleep_flags);
|
||||
// Check if the power domain was powered down
|
||||
TEST_ASSERT_EQUAL(pd_top_down ? PMU_SLEEP_PD_TOP : 0, sleep_ctx.sleep_flags & PMU_SLEEP_PD_TOP);
|
||||
#endif
|
||||
|
||||
esp_sleep_set_sleep_context(NULL);
|
||||
}
|
||||
|
||||
static esp_err_t eth_recv_esp_emac_check_cb(esp_eth_handle_t hdl, uint8_t *buffer, uint32_t length, void *priv, void *info)
|
||||
{
|
||||
emac_frame_t *frame = (emac_frame_t *)buffer;
|
||||
|
||||
if (frame->proto == ntohs(ETH_TEST_ETHERTYPE)) {
|
||||
if (frame->dest[0] == 0x01 && frame->dest[1] == 0x00 && frame->dest[2] == 0x5E) {
|
||||
SemaphoreHandle_t sem = (SemaphoreHandle_t)priv;
|
||||
xSemaphoreGive(sem);
|
||||
}
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void cmd_ping_on_ping_success(esp_ping_handle_t hdl, void *args)
|
||||
{
|
||||
uint8_t ttl;
|
||||
uint16_t seqno;
|
||||
uint32_t elapsed_time, recv_len;
|
||||
ip_addr_t target_addr;
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_TTL, &ttl, sizeof(ttl));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_SIZE, &recv_len, sizeof(recv_len));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &elapsed_time, sizeof(elapsed_time));
|
||||
printf("%" PRIu32 " bytes from %s icmp_seq=%" PRIu16 " ttl=%" PRIu16 " time=%" PRIu32 " ms\n",
|
||||
recv_len, ipaddr_ntoa((ip_addr_t *)&target_addr), seqno, ttl, elapsed_time);
|
||||
}
|
||||
|
||||
static void cmd_ping_on_ping_timeout(esp_ping_handle_t hdl, void *args)
|
||||
{
|
||||
uint16_t seqno;
|
||||
ip_addr_t target_addr;
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_SEQNO, &seqno, sizeof(seqno));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||
printf("From %s icmp_seq=%" PRIu16 " timeout\n", ipaddr_ntoa((ip_addr_t *)&target_addr), seqno);
|
||||
}
|
||||
|
||||
static void cmd_ping_on_ping_end(esp_ping_handle_t hdl, void *args)
|
||||
{
|
||||
ip_addr_t target_addr;
|
||||
uint32_t transmitted;
|
||||
uint32_t received;
|
||||
uint32_t total_time_ms;
|
||||
uint32_t loss;
|
||||
SemaphoreHandle_t sem = (SemaphoreHandle_t)args;
|
||||
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_IPADDR, &target_addr, sizeof(target_addr));
|
||||
esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms));
|
||||
|
||||
if (transmitted > 0) {
|
||||
loss = (uint32_t)((1 - ((float)received) / transmitted) * 100);
|
||||
} else {
|
||||
loss = 0;
|
||||
}
|
||||
if (IP_IS_V4(&target_addr)) {
|
||||
printf("\n--- %s ping statistics ---\n", inet_ntoa(*ip_2_ip4(&target_addr)));
|
||||
} else {
|
||||
printf("\n--- %s ping statistics ---\n", inet6_ntoa(*ip_2_ip6(&target_addr)));
|
||||
}
|
||||
printf("%" PRIu32 " packets transmitted, %" PRIu32 " received, %" PRIu32 "%% packet loss, time %" PRIu32 "ms\n",
|
||||
transmitted, received, loss, total_time_ms);
|
||||
|
||||
esp_ping_delete_session(hdl);
|
||||
TEST_ASSERT_EQUAL(0, loss);
|
||||
TEST_ASSERT_EQUAL(ETH_PING_CNT, transmitted);
|
||||
TEST_ASSERT_EQUAL(ETH_PING_CNT, received);
|
||||
xSemaphoreGive(sem);
|
||||
}
|
||||
|
||||
static void ping_start(const esp_ip4_addr_t *ip, SemaphoreHandle_t sem)
|
||||
{
|
||||
esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG();
|
||||
config.count = ETH_PING_CNT;
|
||||
config.timeout_ms = ETH_PING_TIMEOUT_MS;
|
||||
config.interval_ms = ETH_PING_INTERVAL_MS;
|
||||
|
||||
ip4_addr_set_u32(ip_2_ip4(&config.target_addr), ip->addr);
|
||||
config.target_addr.type = IPADDR_TYPE_V4;
|
||||
|
||||
/* set callback functions */
|
||||
esp_ping_callbacks_t cbs = {
|
||||
.cb_args = sem,
|
||||
.on_ping_success = cmd_ping_on_ping_success,
|
||||
.on_ping_timeout = cmd_ping_on_ping_timeout,
|
||||
.on_ping_end = cmd_ping_on_ping_end
|
||||
};
|
||||
esp_ping_handle_t ping;
|
||||
esp_ping_new_session(&config, &cbs, &ping);
|
||||
esp_ping_start(ping);
|
||||
}
|
||||
|
||||
static void test_emac_sleep_retention(bool pd_top_down)
|
||||
{
|
||||
test_case_uses_tcpip();
|
||||
TEST_ESP_OK(esp_event_loop_create_default());
|
||||
// create TCP/IP netif
|
||||
esp_netif_config_t netif_cfg = ESP_NETIF_DEFAULT_ETH();
|
||||
esp_netif_t *eth_netif = esp_netif_new(&netif_cfg);
|
||||
|
||||
// Initialize Ethernet
|
||||
esp_eth_mac_t *mac = mac_init(NULL, NULL);
|
||||
TEST_ASSERT_NOT_NULL(mac);
|
||||
esp_eth_phy_t *phy = phy_init(NULL);
|
||||
TEST_ASSERT_NOT_NULL(phy);
|
||||
|
||||
esp_eth_config_t config = ETH_DEFAULT_CONFIG(mac, phy);
|
||||
esp_eth_handle_t eth_handle = NULL;
|
||||
TEST_ESP_OK(esp_eth_driver_install(&config, ð_handle));
|
||||
extra_eth_config(eth_handle);
|
||||
// combine driver with netif
|
||||
esp_eth_netif_glue_handle_t glue = esp_eth_new_netif_glue(eth_handle);
|
||||
TEST_ESP_OK(esp_netif_attach(eth_netif, glue));
|
||||
|
||||
// Register event handlers
|
||||
EventGroupHandle_t eth_event_group = xEventGroupCreate();
|
||||
TEST_ASSERT_NOT_NULL(eth_event_group);
|
||||
TEST_ESP_OK(esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID, ð_event_handler, eth_event_group));
|
||||
TEST_ESP_OK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &got_ip_event_handler, eth_event_group));
|
||||
|
||||
uint8_t mac_addr[ETH_ADDR_LEN];
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr));
|
||||
|
||||
// -------- Verify retention when Ethernet is stopped --------
|
||||
eth_test_start_sleep(eth_handle, pd_top_down);
|
||||
uint8_t mac_addr_post_sleep[ETH_ADDR_LEN];
|
||||
// Verify that EMAC configuration was retained by checking MAC address
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr_post_sleep));
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(mac_addr, mac_addr_post_sleep, ETH_ADDR_LEN);
|
||||
// verify that EMAC is not started
|
||||
emac_dma_soc_regs_t dma_regs = &EMAC_DMA;
|
||||
emac_mac_soc_regs_t mac_regs = &EMAC_MAC;
|
||||
TEST_ASSERT_EQUAL(0, dma_regs->dmaoperation_mode.start_stop_rx);
|
||||
TEST_ASSERT_EQUAL(0, dma_regs->dmaoperation_mode.start_stop_transmission_command);
|
||||
TEST_ASSERT_EQUAL(0, mac_regs->gmacconfig.rx);
|
||||
TEST_ASSERT_EQUAL(0, mac_regs->gmacconfig.tx);
|
||||
|
||||
// Start Ethernet
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
||||
EventBits_t bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(ETH_START_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT);
|
||||
|
||||
// Wait for Ethernet connection
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
|
||||
|
||||
// wait for IP lease
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true, pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT);
|
||||
|
||||
// ----- Verify EMAC and full IP stack is still working after sleep -----
|
||||
eth_test_start_sleep(eth_handle, pd_top_down);
|
||||
|
||||
SemaphoreHandle_t sem = xSemaphoreCreateBinary();
|
||||
TEST_ASSERT_NOT_NULL(sem);
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(eth_netif, &ip_info);
|
||||
|
||||
// Verify functionality of MAC and the full IP stack
|
||||
ping_start(&ip_info.gw, sem);
|
||||
|
||||
// wait for ping to finish
|
||||
TEST_ASSERT_EQUAL(pdPASS, xSemaphoreTake(sem, pdMS_TO_TICKS(ETH_PING_SEM_TIMEOUT_MS)));
|
||||
|
||||
// ----- Verify MAC filter retention -----
|
||||
// Stop Ethernet to be able to set loopback
|
||||
TEST_ESP_OK(esp_eth_stop(eth_handle));
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
|
||||
|
||||
// Set loopback to simplify test
|
||||
bool loopback_en = true;
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_S_PHY_LOOPBACK, &loopback_en));
|
||||
TEST_ESP_OK(esp_eth_update_input_path_info(eth_handle, eth_recv_esp_emac_check_cb, sem));
|
||||
|
||||
// Start Ethernet
|
||||
TEST_ESP_OK(esp_eth_start(eth_handle));
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(ETH_START_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT);
|
||||
|
||||
// Wait for Ethernet connection
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, pdTRUE, pdTRUE, pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
|
||||
|
||||
ESP_LOGW(TAG, "Add multicast addresses to filter until it's full (add cmd fails)");
|
||||
uint8_t multicast_addr[ETH_ADDR_LEN] = {0x01, 0x00, 0x5E, 0x00, 0x00, 0x01};
|
||||
esp_err_t ret;
|
||||
uint32_t mcast_addr_count = 0;
|
||||
do {
|
||||
ret = esp_eth_ioctl(eth_handle, ETH_CMD_ADD_MAC_FILTER, multicast_addr);
|
||||
if (ret == ESP_OK) {
|
||||
mcast_addr_count++;
|
||||
multicast_addr[ETH_ADDR_LEN-1]++; // increment last field
|
||||
}
|
||||
} while (ret == ESP_OK);
|
||||
multicast_addr[ETH_ADDR_LEN-1] = 0x01;
|
||||
ESP_LOGI(TAG, "Added %" PRIu32 " multicast addresses", mcast_addr_count);
|
||||
|
||||
// Let's sleep
|
||||
eth_test_start_sleep(eth_handle, pd_top_down);
|
||||
|
||||
// Create multicast frame and send it
|
||||
emac_frame_t *eth_frame = malloc(60);
|
||||
TEST_ASSERT_NOT_NULL(eth_frame);
|
||||
memcpy(eth_frame->dest, multicast_addr, ETH_ADDR_LEN);
|
||||
esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, eth_frame->src);
|
||||
eth_frame->proto = htons(ETH_TEST_ETHERTYPE);
|
||||
|
||||
uint32_t mcast_recv_cnt = 0;
|
||||
for (uint32_t i = 0; i < mcast_addr_count; i++) {
|
||||
esp_eth_transmit(eth_handle, eth_frame, 60);
|
||||
eth_frame->dest[ETH_ADDR_LEN-1]++;
|
||||
if (xSemaphoreTake(sem, pdMS_TO_TICKS(ETH_RECV_TIMEOUT_MS)) == pdFAIL) {
|
||||
break;
|
||||
}
|
||||
mcast_recv_cnt++;
|
||||
}
|
||||
free(eth_frame);
|
||||
TEST_ASSERT_EQUAL(mcast_addr_count, mcast_recv_cnt);
|
||||
|
||||
// stop Ethernet driver
|
||||
TEST_ESP_OK(esp_eth_stop(eth_handle));
|
||||
/* wait for stop stop */
|
||||
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true, pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
|
||||
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
|
||||
|
||||
// -------- Verify retention when Ethernet is stopped (when link is up) --------
|
||||
eth_test_start_sleep(eth_handle, pd_top_down);
|
||||
memset(mac_addr_post_sleep, 0, ETH_ADDR_LEN);
|
||||
TEST_ESP_OK(esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr_post_sleep));
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY(mac_addr, mac_addr_post_sleep, ETH_ADDR_LEN);
|
||||
// verify that EMAC is not started
|
||||
TEST_ASSERT_EQUAL(0, dma_regs->dmaoperation_mode.start_stop_rx);
|
||||
TEST_ASSERT_EQUAL(0, dma_regs->dmaoperation_mode.start_stop_transmission_command);
|
||||
TEST_ASSERT_EQUAL(0, mac_regs->gmacconfig.rx);
|
||||
TEST_ASSERT_EQUAL(0, mac_regs->gmacconfig.tx);
|
||||
|
||||
TEST_ESP_OK(esp_eth_del_netif_glue(glue));
|
||||
/* driver should be uninstalled within 2 seconds */
|
||||
TEST_ESP_OK(esp_eth_driver_uninstall(eth_handle));
|
||||
TEST_ESP_OK(phy->del(phy));
|
||||
TEST_ESP_OK(mac->del(mac));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(IP_EVENT, IP_EVENT_ETH_GOT_IP, got_ip_event_handler));
|
||||
TEST_ESP_OK(esp_event_handler_unregister(ETH_EVENT, ESP_EVENT_ANY_ID, eth_event_handler));
|
||||
esp_netif_destroy(eth_netif);
|
||||
TEST_ESP_OK(esp_event_loop_delete_default());
|
||||
extra_cleanup();
|
||||
vEventGroupDelete(eth_event_group);
|
||||
vSemaphoreDelete(sem);
|
||||
}
|
||||
|
||||
TEST_CASE("internal emac sleep retention", "[sleep_retention]")
|
||||
{
|
||||
ESP_LOGI(TAG, "Testing with PD_TOP powered up");
|
||||
test_emac_sleep_retention(false);
|
||||
|
||||
#if ESP_SLEEP_POWER_DOWN_CPU
|
||||
ESP_LOGI(TAG, "Testing with PD_TOP powered down");
|
||||
test_emac_sleep_retention(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
@@ -4,10 +4,10 @@ import contextlib
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
from collections.abc import Iterator
|
||||
from multiprocessing import Pipe
|
||||
from multiprocessing import Process
|
||||
from multiprocessing import connection
|
||||
from typing import Iterator
|
||||
|
||||
import pytest
|
||||
from pytest_embedded_idf import IdfDut
|
||||
@@ -18,7 +18,7 @@ from scapy.all import raw
|
||||
ETH_TYPE = 0x3300
|
||||
|
||||
|
||||
class EthTestIntf(object):
|
||||
class EthTestIntf:
|
||||
def __init__(self, eth_type: int, my_if: str = ''):
|
||||
self.target_if = ''
|
||||
self.eth_type = eth_type
|
||||
@@ -449,3 +449,17 @@ def test_esp_eth_dm9051(dut: IdfDut) -> None:
|
||||
ethernet_l2_test(dut)
|
||||
dut.serial.hard_reset()
|
||||
ethernet_heap_alloc_test(dut)
|
||||
|
||||
|
||||
# ----------- EMAC Sleep Retention -----------
|
||||
@pytest.mark.eth_ip101
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'emac_sleep_retention',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
|
||||
def test_emac_sleep_retention(dut: IdfDut) -> None:
|
||||
dut.run_all_single_board_cases(group='sleep_retention', timeout=120)
|
||||
|
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_SPI_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_DM9051=y
|
||||
|
@@ -3,7 +3,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_DP83848=y
|
||||
|
@@ -3,7 +3,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8041=y
|
||||
|
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_SPI_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL=y
|
||||
|
@@ -3,7 +3,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_RTL8201=y
|
||||
|
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_SPI_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_W5500=y
|
||||
|
@@ -0,0 +1,12 @@
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_TARGET_USE_DEFAULT_EMAC_CONFIG=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y
|
||||
|
||||
CONFIG_ESP_SLEEP_DEBUG=y
|
||||
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
|
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_SPI_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_DM9051=y
|
||||
|
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_SPI_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_KSZ8851SNL=y
|
||||
|
@@ -2,7 +2,7 @@ CONFIG_IDF_TARGET="esp32"
|
||||
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_SPI_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_W5500=y
|
||||
|
@@ -6,7 +6,7 @@ CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y
|
||||
|
@@ -6,7 +6,7 @@ CONFIG_ESP32_RTCDATA_IN_FAST_MEM=y
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ESP_TASK_WDT=n
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
||||
|
||||
CONFIG_TARGET_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_TARGET_ETH_PHY_DEVICE_IP101=y
|
||||
|
@@ -295,6 +295,10 @@ bool peripheral_domain_pd_allowed(void)
|
||||
mask.bitmap[SLEEP_RETENTION_MODULE_SDM0 >> 5] |= BIT(SLEEP_RETENTION_MODULE_SDM0 % 32);
|
||||
#endif
|
||||
|
||||
#if SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
mask.bitmap[SLEEP_RETENTION_MODULE_EMAC >> 5] |= BIT(SLEEP_RETENTION_MODULE_EMAC % 32);
|
||||
#endif
|
||||
|
||||
const sleep_retention_module_bitmap_t peripheral_domain_inited_modules = sleep_retention_module_bitmap_and(inited_modules, mask);
|
||||
const sleep_retention_module_bitmap_t peripheral_domain_created_modules = sleep_retention_module_bitmap_and(created_modules, mask);
|
||||
return sleep_retention_module_bitmap_eq(peripheral_domain_inited_modules, peripheral_domain_created_modules);
|
||||
|
@@ -65,6 +65,10 @@ void emac_hal_set_rx_tx_desc_addr(emac_hal_context_t *hal, eth_dma_rx_descriptor
|
||||
|
||||
void emac_hal_init_mac_default(emac_hal_context_t *hal)
|
||||
{
|
||||
/* EMACINTMASK */
|
||||
/* Disable (mask) all interrupts */
|
||||
emac_ll_disable_corresponding_emac_intr(hal->mac_regs, 0xFFFFFFFF);
|
||||
|
||||
/* MACCR Configuration */
|
||||
/* Enable the watchdog on the receiver, frame longer than 2048 Bytes is not allowed */
|
||||
emac_ll_watchdog_enable(hal->mac_regs, true);
|
||||
|
@@ -127,9 +127,14 @@ extern "C" {
|
||||
#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) */
|
||||
/* EMAC interrupt enable (referring to emacintmask register in emac_mac_struct.h)*/
|
||||
#define EMAC_LL_MAC_INTR_LOW_POWER_IDLE_ENABLE 0x00000400U
|
||||
#define EMAC_LL_MAC_INTR_POWER_MANAGEMENT_MOD_ENABLE 0x00000008U
|
||||
|
||||
/* Enable needed DMA 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)
|
||||
|
||||
|
||||
/* Maximum number of MAC address to be filtered */
|
||||
#define EMAC_LL_MAX_MAC_ADDR_NUM 8
|
||||
|
||||
@@ -385,6 +390,22 @@ static inline uint32_t emac_ll_read_debug_reg(emac_mac_dev_t *mac_regs)
|
||||
return mac_regs->emacdebug.val;
|
||||
}
|
||||
|
||||
/* pmt_csr */
|
||||
static inline void emac_ll_power_down_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->pmt_csr.pwrdwn = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_magic_packet_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->pmt_csr.mgkpkten = enable;
|
||||
}
|
||||
|
||||
static inline bool emac_ll_get_magic_packet_received(emac_mac_dev_t *mac_regs)
|
||||
{
|
||||
return mac_regs->pmt_csr.mgkprcvd;
|
||||
}
|
||||
|
||||
/* emacmiidata */
|
||||
static inline void emac_ll_set_phy_data(emac_mac_dev_t *mac_regs, uint32_t data)
|
||||
{
|
||||
@@ -403,6 +424,16 @@ static inline void emac_ll_set_addr(emac_mac_dev_t *mac_regs, const uint8_t *add
|
||||
mac_regs->emacaddr0low = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | (addr[0]);
|
||||
}
|
||||
|
||||
static inline void emac_ll_get_addr(emac_mac_dev_t *mac_regs, uint8_t *addr)
|
||||
{
|
||||
addr[0] = mac_regs->emacaddr0low & 0xFF;
|
||||
addr[1] = (mac_regs->emacaddr0low >> 8) & 0xFF;
|
||||
addr[2] = (mac_regs->emacaddr0low >> 16) & 0xFF;
|
||||
addr[3] = (mac_regs->emacaddr0low >> 24) & 0xFF;
|
||||
addr[4] = mac_regs->emacaddr0high.address0_hi & 0xFF;
|
||||
addr[5] = (mac_regs->emacaddr0high.address0_hi >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
/* emacaddrN */
|
||||
static inline void emac_ll_add_addr_filter(emac_mac_dev_t *mac_regs, uint8_t addr_num, const uint8_t *mac_addr, uint8_t mask, bool filter_for_source)
|
||||
{
|
||||
@@ -420,12 +451,12 @@ static inline bool emac_ll_get_addr_filter(emac_mac_dev_t *mac_regs, uint8_t add
|
||||
addr_num = addr_num - 1; // MAC Address1 is located at emacaddr[0]
|
||||
if (mac_regs->emacaddr[addr_num].emacaddrhigh.address_enable) {
|
||||
if (mac_addr != NULL) {
|
||||
*(&mac_addr[0]) = mac_regs->emacaddr[addr_num].emacaddrlow & 0xFF;
|
||||
*(&mac_addr[1]) = (mac_regs->emacaddr[addr_num].emacaddrlow >> 8) & 0xFF;
|
||||
*(&mac_addr[2]) = (mac_regs->emacaddr[addr_num].emacaddrlow >> 16) & 0xFF;
|
||||
*(&mac_addr[3]) = (mac_regs->emacaddr[addr_num].emacaddrlow >> 24) & 0xFF;
|
||||
*(&mac_addr[4]) = mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi & 0xFF;
|
||||
*(&mac_addr[5]) = (mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi >> 8) & 0xFF;
|
||||
mac_addr[0] = mac_regs->emacaddr[addr_num].emacaddrlow & 0xFF;
|
||||
mac_addr[1] = (mac_regs->emacaddr[addr_num].emacaddrlow >> 8) & 0xFF;
|
||||
mac_addr[2] = (mac_regs->emacaddr[addr_num].emacaddrlow >> 16) & 0xFF;
|
||||
mac_addr[3] = (mac_regs->emacaddr[addr_num].emacaddrlow >> 24) & 0xFF;
|
||||
mac_addr[4] = mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi & 0xFF;
|
||||
mac_addr[5] = (mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi >> 8) & 0xFF;
|
||||
}
|
||||
if (mask != NULL) {
|
||||
*mask = mac_regs->emacaddr[addr_num].emacaddrhigh.mask_byte_control;
|
||||
@@ -446,6 +477,21 @@ static inline void emac_ll_rm_addr_filter(emac_mac_dev_t *mac_regs, uint8_t addr
|
||||
mac_regs->emacaddr[addr_num].emacaddrlow = 0;
|
||||
}
|
||||
|
||||
/* emacintmask */
|
||||
static inline void emac_ll_enable_corresponding_emac_intr(emac_mac_dev_t *mac_regs, uint32_t mask)
|
||||
{
|
||||
uint32_t temp_mask = mac_regs->emacintmask.val;
|
||||
temp_mask &= ~mask;
|
||||
mac_regs->emacintmask.val = temp_mask;
|
||||
}
|
||||
|
||||
static inline void emac_ll_disable_corresponding_emac_intr(emac_mac_dev_t *mac_regs, uint32_t mask)
|
||||
{
|
||||
uint32_t temp_mask = mac_regs->emacintmask.val;
|
||||
temp_mask |= mask;
|
||||
mac_regs->emacintmask.val = temp_mask;
|
||||
}
|
||||
|
||||
/*************** End of mac regs operation *********************/
|
||||
|
||||
/************** Start of dma regs operation ********************/
|
||||
|
@@ -361,6 +361,22 @@ static inline uint32_t emac_ll_read_debug_reg(emac_mac_dev_t *mac_regs)
|
||||
return mac_regs->emacdebug.val;
|
||||
}
|
||||
|
||||
/* pmt_csr */
|
||||
static inline void emac_ll_power_down_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->pmt_csr.pwrdwn = enable;
|
||||
}
|
||||
|
||||
static inline void emac_ll_magic_packet_enable(emac_mac_dev_t *mac_regs, bool enable)
|
||||
{
|
||||
mac_regs->pmt_csr.mgkpkten = enable;
|
||||
}
|
||||
|
||||
static inline bool emac_ll_get_magic_packet_received(emac_mac_dev_t *mac_regs)
|
||||
{
|
||||
return mac_regs->pmt_csr.mgkprcvd;
|
||||
}
|
||||
|
||||
/* emacmiidata */
|
||||
static inline void emac_ll_set_phy_data(emac_mac_dev_t *mac_regs, uint32_t data)
|
||||
{
|
||||
@@ -379,6 +395,16 @@ static inline void emac_ll_set_addr(emac_mac_dev_t *mac_regs, const uint8_t *add
|
||||
mac_regs->emacaddr0low = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | (addr[0]);
|
||||
}
|
||||
|
||||
static inline void emac_ll_get_addr(emac_mac_dev_t *mac_regs, uint8_t *addr)
|
||||
{
|
||||
addr[0] = mac_regs->emacaddr0low & 0xFF;
|
||||
addr[1] = (mac_regs->emacaddr0low >> 8) & 0xFF;
|
||||
addr[2] = (mac_regs->emacaddr0low >> 16) & 0xFF;
|
||||
addr[3] = (mac_regs->emacaddr0low >> 24) & 0xFF;
|
||||
addr[4] = mac_regs->emacaddr0high.address0_hi & 0xFF;
|
||||
addr[5] = (mac_regs->emacaddr0high.address0_hi >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
/* emacaddrN */
|
||||
static inline void emac_ll_add_addr_filter(emac_mac_dev_t *mac_regs, uint8_t addr_num, const uint8_t *mac_addr, uint8_t mask, bool filter_for_source)
|
||||
{
|
||||
@@ -396,12 +422,12 @@ static inline bool emac_ll_get_addr_filter(emac_mac_dev_t *mac_regs, uint8_t add
|
||||
addr_num = addr_num - 1; // MAC Address1 is located at emacaddr[0]
|
||||
if (mac_regs->emacaddr[addr_num].emacaddrhigh.address_enable) {
|
||||
if (mac_addr != NULL) {
|
||||
*(&mac_addr[0]) = mac_regs->emacaddr[addr_num].emacaddrlow & 0xFF;
|
||||
*(&mac_addr[1]) = (mac_regs->emacaddr[addr_num].emacaddrlow >> 8) & 0xFF;
|
||||
*(&mac_addr[2]) = (mac_regs->emacaddr[addr_num].emacaddrlow >> 16) & 0xFF;
|
||||
*(&mac_addr[3]) = (mac_regs->emacaddr[addr_num].emacaddrlow >> 24) & 0xFF;
|
||||
*(&mac_addr[4]) = mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi & 0xFF;
|
||||
*(&mac_addr[5]) = (mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi >> 8) & 0xFF;
|
||||
mac_addr[0] = mac_regs->emacaddr[addr_num].emacaddrlow & 0xFF;
|
||||
mac_addr[1] = (mac_regs->emacaddr[addr_num].emacaddrlow >> 8) & 0xFF;
|
||||
mac_addr[2] = (mac_regs->emacaddr[addr_num].emacaddrlow >> 16) & 0xFF;
|
||||
mac_addr[3] = (mac_regs->emacaddr[addr_num].emacaddrlow >> 24) & 0xFF;
|
||||
mac_addr[4] = mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi & 0xFF;
|
||||
mac_addr[5] = (mac_regs->emacaddr[addr_num].emacaddrhigh.mac_address_hi >> 8) & 0xFF;
|
||||
}
|
||||
if (mask != NULL) {
|
||||
*mask = mac_regs->emacaddr[addr_num].emacaddrhigh.mask_byte_control;
|
||||
|
@@ -276,6 +276,8 @@ void emac_hal_set_phy_cmd(emac_hal_context_t *hal, uint32_t phy_addr, uint32_t p
|
||||
|
||||
void emac_hal_set_address(emac_hal_context_t *hal, uint8_t *mac_addr);
|
||||
|
||||
#define emac_hal_get_address(hal, mac_addr) emac_ll_get_addr((hal)->mac_regs, mac_addr)
|
||||
|
||||
esp_err_t emac_hal_add_addr_da_filter(emac_hal_context_t *hal, const uint8_t *mac_addr, uint8_t addr_num);
|
||||
|
||||
esp_err_t emac_hal_get_addr_da_filter(emac_hal_context_t *hal, uint8_t *mac_addr, uint8_t addr_num);
|
||||
|
@@ -1,10 +1,13 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "soc/emac_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#if __has_include("soc/emac_reg.h")
|
||||
#include "soc/emac_reg.h"
|
||||
#endif
|
||||
|
||||
const emac_io_info_t emac_io_idx = {
|
||||
.mdc_idx = MII_MDC_PAD_OUT_IDX,
|
||||
@@ -208,3 +211,148 @@ const emac_rmii_iomux_info_t emac_rmii_iomux_pins = {
|
||||
};
|
||||
|
||||
const emac_mii_iomux_info_t emac_mii_iomux_pins = { 0 };
|
||||
|
||||
/* Registers in retention context:
|
||||
DMA:
|
||||
0 Bus Mode Register
|
||||
3 Receive Descriptor List Address Register (can write to this register only when Rx DMA has stopped)
|
||||
4 Transmit Descriptor List Address Register - same as above
|
||||
6 Operation Mode Register
|
||||
7 Interrupt Enable Register
|
||||
18 Current Host Transmit Descriptor Register (RO!) => save to Transmit Descriptor Reg 4
|
||||
19 Current Host Receive Descriptor Register (RO) => save to Receive Descriptor Reg 3
|
||||
|
||||
MAC:
|
||||
0 MAC Configuration Register
|
||||
1 MAC Frame Filter
|
||||
4 GMII Address Register
|
||||
6 Flow Control Register
|
||||
15 Interrupt Mask Register
|
||||
16 MAC Address0 High Register
|
||||
17 MAC Address0 Low Register
|
||||
18 - (18 + n*2) MAC Address1-n Registers
|
||||
|
||||
IEEE1588:
|
||||
no need to save/restore since such use case does not make sense (system cannot sleep when wants to maintain nsec sync precision)
|
||||
*/
|
||||
#if SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
#define EMAC_MAC_RETENTION_REGS_CNT 4
|
||||
#define EMAC_MAC_RETENTION_REGS_BASE (DR_REG_EMAC_BASE + 0x0)
|
||||
static const uint32_t emac_mac_regs_map[4] = {0x53, 0x0, 0x0, 0x0};
|
||||
|
||||
#define EMAC_DMA_RETENTION_REGS_CNT 3
|
||||
#define EMAC_DMA_RETENTION_REGS_BASE (DR_REG_EMAC_BASE + 0x1000)
|
||||
static const uint32_t emac_dma_regs_map[4] = {0xc1, 0x0, 0x0, 0x0};
|
||||
|
||||
const regdma_entries_config_t emac_regdma_entries[] = {
|
||||
// backup stage: stop TX/RX DMA
|
||||
[0] = {
|
||||
.config = REGDMA_LINK_WRITE_INIT(REGDMA_EMAC_LINK(0x00),
|
||||
EMAC_OPERATIONMODE_REG, 0x0, EMAC_SR_M | EMAC_ST_M, 0, 1),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
// backup stage: wait for the TX done (debug reg);
|
||||
// IDF-13600
|
||||
[1] = {
|
||||
.config = REGDMA_LINK_WAIT_INIT(REGDMA_EMAC_LINK(0x01),
|
||||
EMAC_DEBUG_REG, 0x0, EMAC_TFCSTS_M, 0, 1),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// backup stage: stop TX/RX in MAC layer
|
||||
[2] = {
|
||||
.config = REGDMA_LINK_WRITE_INIT(REGDMA_EMAC_LINK(0x02),
|
||||
EMAC_MACCONFIGURATION_REG, 0x0, EMAC_RE_M | EMAC_RE_M, 0, 1),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// restore stage: EMAC SW reset
|
||||
[3] = {
|
||||
.config = REGDMA_LINK_WRITE_INIT(REGDMA_EMAC_LINK(0x03),
|
||||
EMAC_BUSMODE_REG, EMAC_SWR, EMAC_SWR_M, 1, 0),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
// restore stage: wait for the SW reset done
|
||||
[4] = {
|
||||
.config = REGDMA_LINK_WAIT_INIT(REGDMA_EMAC_LINK(0x04),
|
||||
EMAC_BUSMODE_REG, 0x0, EMAC_SWR_M, 1, 0),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// backup stage: save Current Host Tx/Rx Descriptor Register
|
||||
// restore stage: restore to Rx/Tx Descriptor List Address Register
|
||||
[5] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_EMAC_LINK(0x05),
|
||||
EMAC_CURRENTHOSTRECEIVEDESCRIPTOR_REG, EMAC_RECEIVEDESCRIPTORLISTADDRESS_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
[6] = {
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_EMAC_LINK(0x06),
|
||||
EMAC_CURRENTHOSTTRANSMITDESCRIPTOR_REG, EMAC_TRANSMITDESCRIPTORLISTADDRESS_REG, 1, 0, 0),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// backup stage: save MAC Configuration Register (0), MAC Frame Filter (1), GMII Address Register (4) and Flow Control Register (6)
|
||||
// restore stage: restore at the same positions
|
||||
[7] = {
|
||||
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_EMAC_LINK(0x07),
|
||||
EMAC_MAC_RETENTION_REGS_BASE, EMAC_MAC_RETENTION_REGS_BASE,
|
||||
EMAC_MAC_RETENTION_REGS_CNT, 0, 0,
|
||||
emac_mac_regs_map[0], emac_mac_regs_map[1],
|
||||
emac_mac_regs_map[2], emac_mac_regs_map[3]),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// backup stage: save DMA Bus Mode Register (0), Operation Mode Register (6) and Interrupt Enable Register (7)
|
||||
// restore stage: restore at the same positions
|
||||
[8] = {
|
||||
.config = REGDMA_LINK_ADDR_MAP_INIT(REGDMA_EMAC_LINK(0x08),
|
||||
EMAC_DMA_RETENTION_REGS_BASE, EMAC_DMA_RETENTION_REGS_BASE,
|
||||
EMAC_DMA_RETENTION_REGS_CNT, 0, 0,
|
||||
emac_dma_regs_map[0], emac_dma_regs_map[1],
|
||||
emac_dma_regs_map[2], emac_dma_regs_map[3]),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// backup stage: save Interrupt Mask Register (15) and MAC Address Registers (16-...)
|
||||
// restore stage: restore at the same positions
|
||||
[9] = {
|
||||
// 1 word for int. reg, 2 words for MAC Addr0, 8*2 words for MAC Addr1-8
|
||||
.config = REGDMA_LINK_CONTINUOUS_INIT(REGDMA_EMAC_LINK(0x09),
|
||||
EMAC_INTERRUPTMASK_REG, EMAC_INTERRUPTMASK_REG, 1 + 2 + 8 * 2, 0, 0),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
//** ------------------------------------------------------------------------------------------------
|
||||
// Below steps are to be performed only when link is up and EMAC is started
|
||||
//** ------------------------------------------------------------------------------------------------
|
||||
// restore stage: start TX in MAC layer
|
||||
[EMAC_REGDMA_LINK_EMAC_START_BEGIN] = {
|
||||
.config = REGDMA_LINK_WRITE_INIT(REGDMA_EMAC_LINK(EMAC_REGDMA_LINK_EMAC_START_BEGIN),
|
||||
EMAC_MACCONFIGURATION_REG, EMAC_TE, EMAC_TE_M, 1, 1),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// restore stage: start DMA TX and RX
|
||||
[EMAC_REGDMA_LINK_EMAC_START_BEGIN + 1] = {
|
||||
.config = REGDMA_LINK_WRITE_INIT(REGDMA_EMAC_LINK((EMAC_REGDMA_LINK_EMAC_START_BEGIN + 1)),
|
||||
EMAC_OPERATIONMODE_REG, EMAC_ST | EMAC_SR, EMAC_ST_M | EMAC_SR_M, 1, 1),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
|
||||
// restore stage: start RX in MAC layer
|
||||
[EMAC_REGDMA_LINK_EMAC_START_BEGIN + 2] = {
|
||||
.config = REGDMA_LINK_WRITE_INIT(REGDMA_EMAC_LINK((EMAC_REGDMA_LINK_EMAC_START_BEGIN + 2)),
|
||||
EMAC_MACCONFIGURATION_REG, EMAC_RE, EMAC_RE_M, 1, 1),
|
||||
.owner = ENTRY(0)
|
||||
},
|
||||
};
|
||||
|
||||
const emac_reg_retention_info_t emac_reg_retention_info = {
|
||||
.module_id = SLEEP_RETENTION_MODULE_EMAC,
|
||||
.entry_array = emac_regdma_entries,
|
||||
.array_size = ARRAY_SIZE(emac_regdma_entries)
|
||||
};
|
||||
|
||||
#endif // SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
|
@@ -2091,6 +2091,10 @@ config SOC_EMAC_MII_USE_GPIO_MATRIX
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_JPEG_CODEC_SUPPORTED
|
||||
bool
|
||||
default y
|
||||
|
@@ -60,6 +60,7 @@ typedef enum periph_retention_module {
|
||||
SLEEP_RETENTION_MODULE_MCPWM0 = 34,
|
||||
SLEEP_RETENTION_MODULE_MCPWM1 = 35,
|
||||
SLEEP_RETENTION_MODULE_SDM0 = 36,
|
||||
SLEEP_RETENTION_MODULE_EMAC = 37,
|
||||
|
||||
SLEEP_RETENTION_MODULE_MAX = SOC_PM_RETENTION_MODULE_NUM - 1
|
||||
} periph_retention_module_t;
|
||||
|
@@ -782,6 +782,7 @@
|
||||
#define SOC_EMAC_IEEE1588V2_SUPPORTED (1) /*!< EMAC Supports IEEE1588v2 time stamping */
|
||||
#define SOC_EMAC_USE_MULTI_IO_MUX (1) /*!< Multiple GPIO pad options exist to connect EMAC signal via IO_MUX */
|
||||
#define SOC_EMAC_MII_USE_GPIO_MATRIX (1) /*!< EMAC MII signals are connected to GPIO pads via GPIO Matrix */
|
||||
#define SOC_EMAC_SUPPORT_SLEEP_RETENTION (1) /*!< EMAC supports register backup/restore in sleep mode */
|
||||
|
||||
/*--------------------------- JPEG --------------------------------*/
|
||||
#define SOC_JPEG_CODEC_SUPPORTED (1)
|
||||
|
7239
components/soc/esp32p4/register/hw_ver1/soc/emac_reg.h
Normal file
7239
components/soc/esp32p4/register/hw_ver1/soc/emac_reg.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2019-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "soc/soc_caps.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_num.h"
|
||||
#if SOC_PAU_SUPPORTED
|
||||
#include "soc/regdma.h"
|
||||
#include "soc/retention_periph_defs.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -83,6 +87,19 @@ extern const emac_io_info_t emac_io_idx;
|
||||
extern const emac_rmii_iomux_info_t emac_rmii_iomux_pins;
|
||||
extern const emac_mii_iomux_info_t emac_mii_iomux_pins;
|
||||
|
||||
#if SOC_PAU_SUPPORTED && SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
#define EMAC_REGDMA_LINK_EMAC_START_BEGIN (10)
|
||||
#define EMAC_REGDMA_LINK_EMAC_START_CNT (3)
|
||||
|
||||
typedef struct {
|
||||
const periph_retention_module_t module_id;
|
||||
const regdma_entries_config_t *entry_array;
|
||||
uint32_t array_size;
|
||||
} emac_reg_retention_info_t;
|
||||
|
||||
extern const emac_reg_retention_info_t emac_reg_retention_info;
|
||||
#endif // SOC_PAU_SUPPORTED && SOC_EMAC_SUPPORT_SLEEP_RETENTION
|
||||
|
||||
#endif // SOC_EMAC_SUPPORTED
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@@ -65,6 +65,7 @@ extern "C" {
|
||||
#define REGDMA_LEDC_LINK(_pri) ((0x24 << 8) | _pri)
|
||||
#define REGDMA_MCPWM_LINK(_pri) ((0x25 << 8) | _pri)
|
||||
#define REGDMA_SDM_LINK(_pri) ((0x26 << 8) | _pri)
|
||||
#define REGDMA_EMAC_LINK(_pri) ((0x27 << 8) | _pri)
|
||||
|
||||
#define REGDMA_MODEM_FE_LINK(_pri) ((0xFF << 8) | _pri)
|
||||
|
||||
@@ -92,6 +93,7 @@ extern "C" {
|
||||
#define REGDMA_LINK_PRI_LEDC REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_MCPWM REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_SDM REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
#define REGDMA_LINK_PRI_EMAC REGDMA_LINK_PRI_GENERAL_PERIPH
|
||||
|
||||
typedef enum {
|
||||
REGDMA_LINK_PRI_0 = 0,
|
||||
|
@@ -152,6 +152,7 @@ The following drivers hold the ``ESP_PM_APB_FREQ_MAX`` lock while the driver is
|
||||
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
|
||||
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
|
||||
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
|
||||
:SOC_EMAC_SUPPORT_SLEEP_RETENTION: - EMAC
|
||||
|
||||
Some peripherals haven't support Light-sleep context retention, or it cannot survive from the register lose. They will prevent the power-down of peripherals even when the feature is enabled.
|
||||
|
||||
|
@@ -152,6 +152,7 @@ ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,
|
||||
:SOC_TWAI_SUPPORT_SLEEP_RETENTION: - All TWAIs
|
||||
:SOC_PARLIO_SUPPORT_SLEEP_RETENTION: - PARL_IO
|
||||
:SOC_SPI_SUPPORT_SLEEP_RETENTION: - All GPSPIs
|
||||
:SOC_EMAC_SUPPORT_SLEEP_RETENTION: - EMAC
|
||||
|
||||
一些外设尚未支持睡眠上下文恢复,或者寄存器丢失后根本无法恢复。即使外设下电功能被启用,它们也会阻止外设下电的发生:
|
||||
|
||||
|
Reference in New Issue
Block a user