diff --git a/components/esp_eth/src/esp_eth_mac_esp.c b/components/esp_eth/src/esp_eth_mac_esp.c index 98d08e342917..1de969d7a675 100644 --- a/components/esp_eth/src/esp_eth_mac_esp.c +++ b/components/esp_eth/src/esp_eth_mac_esp.c @@ -57,7 +57,6 @@ typedef struct { uint32_t flow_control_low_water_mark; int smi_mdc_gpio_num; int smi_mdio_gpio_num; - eth_data_interface_t interface; eth_mac_clock_config_t clock_config; uint8_t addr[6]; uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM]; @@ -70,6 +69,9 @@ typedef struct { #endif } emac_esp32_t; +static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl, void **out_descriptors); +static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors); + static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth) { esp_err_t ret = ESP_OK; @@ -336,42 +338,6 @@ 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 APB to access Ethernet peripheral registers */ - periph_module_enable(PERIPH_EMAC_MODULE); - - /* init clock, config gpio, etc */ - if (emac->interface == EMAC_DATA_INTERFACE_MII) { - /* MII interface GPIO initialization */ - emac_hal_iomux_init_mii(); - /* Enable MII clock */ - emac_ll_clock_enable_mii(emac->hal.ext_regs); - } else if (emac->interface == EMAC_DATA_INTERFACE_RMII) { - /* RMII interface GPIO initialization */ - emac_hal_iomux_init_rmii(); - /* If ref_clk is configured as input */ - if (emac->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) { - ESP_GOTO_ON_FALSE(emac->clock_config.rmii.clock_gpio == EMAC_CLK_IN_GPIO, - ESP_ERR_INVALID_ARG, err, TAG, "ESP32 EMAC only support input RMII clock to GPIO0"); - emac_hal_iomux_rmii_clk_input(); - emac_ll_clock_enable_rmii_input(emac->hal.ext_regs); - } else if (emac->clock_config.rmii.clock_mode == EMAC_CLK_OUT) { - ESP_GOTO_ON_FALSE(emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO || - emac->clock_config.rmii.clock_gpio == EMAC_CLK_OUT_GPIO || - emac->clock_config.rmii.clock_gpio == EMAC_CLK_OUT_180_GPIO, - ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock output GPIO"); - emac_hal_iomux_rmii_clk_ouput(emac->clock_config.rmii.clock_gpio); - if (emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) { - REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 6); - } - /* Enable RMII clock */ - emac_ll_clock_enable_rmii_output(emac->hal.ext_regs); - emac_config_apll_clock(); - } else { - ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock mode"); - } - } else { - ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC interface"); - } /* init gpio used by smi interface */ emac_esp32_init_smi_gpio(emac); @@ -417,7 +383,6 @@ static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac) #endif emac_hal_stop(&emac->hal); eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL); - periph_module_disable(PERIPH_EMAC_MODULE); return ESP_OK; } @@ -438,22 +403,8 @@ static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac) static esp_err_t emac_esp32_del(esp_eth_mac_t *mac) { emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent); - esp_intr_free(emac->intr_hdl); -#ifdef CONFIG_PM_ENABLE - if (emac->pm_lock) { - esp_pm_lock_delete(emac->pm_lock); - } -#endif - vTaskDelete(emac->rx_task_hdl); - int i = 0; - for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac->hal.rx_buf[i]); - } - for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - free(emac->hal.tx_buf[i]); - } - free(emac->hal.descriptors); - free(emac); + esp_emac_free_driver_obj(emac, emac->hal.descriptors); + periph_module_disable(PERIPH_EMAC_MODULE); return ESP_OK; } @@ -477,71 +428,173 @@ IRAM_ATTR void emac_isr_default_handler(void *args) #endif } -esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) +static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors) { - esp_err_t ret_code = ESP_OK; - esp_eth_mac_t *ret = NULL; - void *descriptors = NULL; + if (emac) { + if (emac->rx_task_hdl) { + vTaskDelete(emac->rx_task_hdl); + } + if (emac->intr_hdl) { + esp_intr_free(emac->intr_hdl); + } + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + free(emac->tx_buf[i]); + } + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + free(emac->rx_buf[i]); + } +#ifdef CONFIG_PM_ENABLE + if (emac->pm_lock) { + esp_pm_lock_delete(emac->pm_lock); + } +#endif + free(emac); + } + if (descriptors) { + free(descriptors); + } +} + +static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl, void **out_descriptors) +{ + esp_err_t ret = ESP_OK; emac_esp32_t *emac = NULL; - ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set mac config to null"); + void *descriptors = NULL; if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) { emac = heap_caps_calloc(1, sizeof(emac_esp32_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); } else { emac = calloc(1, sizeof(emac_esp32_t)); } - ESP_GOTO_ON_FALSE(emac, NULL, err, TAG, "calloc emac failed"); + ESP_GOTO_ON_FALSE(emac, ESP_ERR_NO_MEM, err, TAG, "no mem for esp emac object"); /* alloc memory for ethernet dma descriptor */ uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) + CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t); descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA); - ESP_GOTO_ON_FALSE(descriptors, NULL, err, TAG, "calloc descriptors failed"); - int i = 0; + ESP_GOTO_ON_FALSE(descriptors, ESP_ERR_NO_MEM, err, TAG, "no mem for descriptors"); /* alloc memory for ethernet dma buffer */ - for (i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { + for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); - if (!(emac->rx_buf[i])) { - goto err; - } + ESP_GOTO_ON_FALSE(emac->rx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for RX DMA buffers"); } - for (i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { + for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA); - if (!(emac->tx_buf[i])) { - goto err; - } + ESP_GOTO_ON_FALSE(emac->tx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for TX DMA buffers"); } - /* initialize hal layer driver */ - emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); - emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; - emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num; - emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num; - ESP_GOTO_ON_FALSE(config->interface == EMAC_DATA_INTERFACE_MII || config->interface == EMAC_DATA_INTERFACE_RMII, - NULL, err, TAG, "invalid EMAC Data Interface"); - emac->interface = config->interface; + /* 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 + /* create rx task */ + BaseType_t core_num = tskNO_AFFINITY; + if (config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { + core_num = cpu_hal_get_core_id(); + } + BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, + config->rx_task_prio, &emac->rx_task_hdl, core_num); + ESP_GOTO_ON_FALSE(xReturned == pdPASS, ESP_FAIL, err, TAG, "create emac_rx task failed"); + + *out_descriptors = descriptors; + *emac_out_hdl = emac; + return ESP_OK; +err: + esp_emac_free_driver_obj(emac, descriptors); + return ret; +} - if (emac->interface == EMAC_DATA_INTERFACE_RMII) { +static esp_err_t esp_emac_config_data_interface(const eth_mac_config_t *config, emac_esp32_t *emac) +{ + esp_err_t ret = ESP_OK; + switch (config->interface) { + case EMAC_DATA_INTERFACE_MII: + emac->clock_config = config->clock_config; + /* MII interface GPIO initialization */ + emac_hal_iomux_init_mii(); + /* Enable MII clock */ + emac_ll_clock_enable_mii(emac->hal.ext_regs); + break; + case EMAC_DATA_INTERFACE_RMII: + // by default, the clock mode is selected at compile time (by Kconfig) if (config->clock_config.rmii.clock_mode == EMAC_CLK_DEFAULT) { -#if CONFIG_ETH_RMII_CLK_INPUT && CONFIG_ETH_RMII_CLK_IN_GPIO == 0 +#if CONFIG_ETH_RMII_CLK_INPUT +#if CONFIG_ETH_RMII_CLK_IN_GPIO == 0 emac->clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN; emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_IN_GPIO; #else #error "ESP32 EMAC only support input RMII clock to GPIO0" -#endif // CONFIG_ETH_RMII_CLK_INPUT && CONFIG_ETH_RMII_CLK_IN_GPIO == 0 - - /* If ref_clk is configured as output */ -#if CONFIG_ETH_RMII_CLK_OUTPUT +#endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0 +#elif CONFIG_ETH_RMII_CLK_OUTPUT emac->clock_config.rmii.clock_mode = EMAC_CLK_OUT; #if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 emac->clock_config.rmii.clock_gpio = 0; #elif CONFIG_ETH_RMII_CLK_OUT_GPIO emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_OUT_GPIO; #endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0 -#endif // CONFIG_ETH_RMII_CLK_OUTPUT +#else +#error "Unsupported RMII clock mode" +#endif } else { emac->clock_config = config->clock_config; } - } else if (emac->interface == EMAC_DATA_INTERFACE_MII) { - emac->clock_config = config->clock_config; + /* RMII interface GPIO initialization */ + emac_hal_iomux_init_rmii(); + /* If ref_clk is configured as input */ + if (emac->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) { + ESP_GOTO_ON_FALSE(emac->clock_config.rmii.clock_gpio == EMAC_CLK_IN_GPIO, + ESP_ERR_INVALID_ARG, err, TAG, "ESP32 EMAC only support input RMII clock to GPIO0"); + emac_hal_iomux_rmii_clk_input(); + emac_ll_clock_enable_rmii_input(emac->hal.ext_regs); + } else if (emac->clock_config.rmii.clock_mode == EMAC_CLK_OUT) { + ESP_GOTO_ON_FALSE(emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO || + emac->clock_config.rmii.clock_gpio == EMAC_CLK_OUT_GPIO || + emac->clock_config.rmii.clock_gpio == EMAC_CLK_OUT_180_GPIO, + ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock output GPIO"); + emac_hal_iomux_rmii_clk_ouput(emac->clock_config.rmii.clock_gpio); + if (emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) { + REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 6); + } + /* Enable RMII clock */ + emac_ll_clock_enable_rmii_output(emac->hal.ext_regs); + emac_config_apll_clock(); + } else { + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock mode"); + } + break; + default: + ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC Data Interface:%d", config->interface); + } +err: + return ret; +} + +esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) +{ + esp_err_t ret_code = ESP_OK; + esp_eth_mac_t *ret = NULL; + void *descriptors = NULL; + emac_esp32_t *emac = NULL; + ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set mac config to null"); + ret_code = esp_emac_alloc_driver_obj(config, &emac, &descriptors); + ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc driver object failed"); + + /* enable APB to access Ethernet peripheral registers */ + periph_module_enable(PERIPH_EMAC_MODULE); + /* initialize hal layer driver */ + emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf); + /* alloc interrupt */ + 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_isr_default_handler, &emac->hal, &(emac->intr_hdl)); + } else { + ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, + emac_isr_default_handler, &emac->hal, &(emac->intr_hdl)); } + ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed"); + ret_code = esp_emac_config_data_interface(config, emac); + ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err_interf, TAG, "config emac interface failed"); + + emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms; + emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num; + emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num; emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK; emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK; emac->parent.set_mediator = emac_esp32_set_mediator; @@ -562,51 +615,11 @@ esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config) emac->parent.enable_flow_ctrl = emac_esp32_enable_flow_ctrl; emac->parent.transmit = emac_esp32_transmit; emac->parent.receive = emac_esp32_receive; - /* 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_isr_default_handler, &emac->hal, &(emac->intr_hdl)); - } else { - ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0, - 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 - ESP_GOTO_ON_FALSE(esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "emac_esp32", &emac->pm_lock) == ESP_OK, NULL, err, TAG, "create pm lock failed"); -#endif - /* create rx task */ - BaseType_t core_num = tskNO_AFFINITY; - if (config->flags & ETH_MAC_FLAG_PIN_TO_CORE) { - core_num = cpu_hal_get_core_id(); - } - BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac, - config->rx_task_prio, &emac->rx_task_hdl, core_num); - ESP_GOTO_ON_FALSE(xReturned == pdPASS, NULL, err, TAG, "create emac_rx task failed"); return &(emac->parent); +err_interf: + periph_module_disable(PERIPH_EMAC_MODULE); err: - if (emac) { - if (emac->rx_task_hdl) { - vTaskDelete(emac->rx_task_hdl); - } - if (emac->intr_hdl) { - esp_intr_free(emac->intr_hdl); - } - for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) { - free(emac->tx_buf[i]); - } - for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) { - free(emac->rx_buf[i]); - } -#ifdef CONFIG_PM_ENABLE - if (emac->pm_lock) { - esp_pm_lock_delete(emac->pm_lock); - } -#endif - free(emac); - } - if (descriptors) { - free(descriptors); - } + esp_emac_free_driver_obj(emac, descriptors); return ret; }