Просмотр исходного кода

emac: configure data interface early

Related to https://github.com/espressif/esp-idf/issues/7227
morris 4 лет назад
Родитель
Сommit
8e069dd755
1 измененных файлов с 143 добавлено и 130 удалено
  1. 143 130
      components/esp_eth/src/esp_eth_mac_esp.c

+ 143 - 130
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;
 }