1 /*
2 * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <string.h>
7 #include <stdlib.h>
8 #include <sys/cdefs.h>
9 #include "driver/periph_ctrl.h"
10 #include "driver/gpio.h"
11 #include "esp_attr.h"
12 #include "esp_log.h"
13 #include "esp_check.h"
14 #include "esp_eth.h"
15 #include "esp_pm.h"
16 #include "esp_system.h"
17 #include "esp_heap_caps.h"
18 #include "esp_intr_alloc.h"
19 #include "esp_private/esp_clk.h"
20 #include "freertos/FreeRTOS.h"
21 #include "freertos/task.h"
22 #include "freertos/semphr.h"
23 #include "hal/cpu_hal.h"
24 #include "hal/emac_hal.h"
25 #include "hal/gpio_hal.h"
26 #include "soc/soc.h"
27 #include "soc/rtc.h"
28 #include "sdkconfig.h"
29 #include "esp_rom_gpio.h"
30 #include "esp_rom_sys.h"
31 #include "hal/emac_ll.h"
32
33 static const char *TAG = "esp.emac";
34
35 #define PHY_OPERATION_TIMEOUT_US (1000)
36 #define MAC_STOP_TIMEOUT_US (250)
37 #define FLOW_CONTROL_LOW_WATER_MARK (CONFIG_ETH_DMA_RX_BUFFER_NUM / 3)
38 #define FLOW_CONTROL_HIGH_WATER_MARK (FLOW_CONTROL_LOW_WATER_MARK * 2)
39
40 typedef struct {
41 esp_eth_mac_t parent;
42 esp_eth_mediator_t *eth;
43 emac_hal_context_t hal;
44 intr_handle_t intr_hdl;
45 TaskHandle_t rx_task_hdl;
46 uint32_t sw_reset_timeout_ms;
47 uint32_t frames_remain;
48 uint32_t free_rx_descriptor;
49 uint32_t flow_control_high_water_mark;
50 uint32_t flow_control_low_water_mark;
51 int smi_mdc_gpio_num;
52 int smi_mdio_gpio_num;
53 eth_mac_clock_config_t clock_config;
54 uint8_t addr[6];
55 uint8_t *rx_buf[CONFIG_ETH_DMA_RX_BUFFER_NUM];
56 uint8_t *tx_buf[CONFIG_ETH_DMA_TX_BUFFER_NUM];
57 bool isr_need_yield;
58 bool flow_ctrl_enabled; // indicates whether the user want to do flow control
59 bool do_flow_ctrl; // indicates whether we need to do software flow control
60 #ifdef CONFIG_PM_ENABLE
61 esp_pm_lock_handle_t pm_lock;
62 #endif
63 } emac_esp32_t;
64
65 static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl, void **out_descriptors);
66 static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors);
67 static esp_err_t emac_esp32_start(esp_eth_mac_t *mac);
68 static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac);
69
emac_esp32_set_mediator(esp_eth_mac_t * mac,esp_eth_mediator_t * eth)70 static esp_err_t emac_esp32_set_mediator(esp_eth_mac_t *mac, esp_eth_mediator_t *eth)
71 {
72 esp_err_t ret = ESP_OK;
73 ESP_GOTO_ON_FALSE(eth, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac's mediator to null");
74 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
75 emac->eth = eth;
76 return ESP_OK;
77 err:
78 return ret;
79 }
80
emac_esp32_write_phy_reg(esp_eth_mac_t * mac,uint32_t phy_addr,uint32_t phy_reg,uint32_t reg_value)81 static esp_err_t emac_esp32_write_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value)
82 {
83 esp_err_t ret = ESP_OK;
84 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
85 ESP_GOTO_ON_FALSE(!emac_ll_is_mii_busy(emac->hal.mac_regs), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
86 emac_ll_set_phy_data(emac->hal.mac_regs, reg_value);
87 emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, true);
88 /* polling the busy flag */
89 uint32_t to = 0;
90 bool busy = true;
91 do {
92 esp_rom_delay_us(100);
93 busy = emac_ll_is_mii_busy(emac->hal.mac_regs);
94 to += 100;
95 } while (busy && to < PHY_OPERATION_TIMEOUT_US);
96 ESP_GOTO_ON_FALSE(!busy, ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
97 return ESP_OK;
98 err:
99 return ret;
100 }
101
emac_esp32_read_phy_reg(esp_eth_mac_t * mac,uint32_t phy_addr,uint32_t phy_reg,uint32_t * reg_value)102 static esp_err_t emac_esp32_read_phy_reg(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value)
103 {
104 esp_err_t ret = ESP_OK;
105 ESP_GOTO_ON_FALSE(reg_value, ESP_ERR_INVALID_ARG, err, TAG, "can't set reg_value to null");
106 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
107 ESP_GOTO_ON_FALSE(!emac_ll_is_mii_busy(emac->hal.mac_regs), ESP_ERR_INVALID_STATE, err, TAG, "phy is busy");
108 emac_hal_set_phy_cmd(&emac->hal, phy_addr, phy_reg, false);
109 /* polling the busy flag */
110 uint32_t to = 0;
111 bool busy = true;
112 do {
113 esp_rom_delay_us(100);
114 busy = emac_ll_is_mii_busy(emac->hal.mac_regs);
115 to += 100;
116 } while (busy && to < PHY_OPERATION_TIMEOUT_US);
117 ESP_GOTO_ON_FALSE(!busy, ESP_ERR_TIMEOUT, err, TAG, "phy is busy");
118 /* Store value */
119 *reg_value = emac_ll_get_phy_data(emac->hal.mac_regs);
120 return ESP_OK;
121 err:
122 return ret;
123 }
124
emac_esp32_set_addr(esp_eth_mac_t * mac,uint8_t * addr)125 static esp_err_t emac_esp32_set_addr(esp_eth_mac_t *mac, uint8_t *addr)
126 {
127 esp_err_t ret = ESP_OK;
128 ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
129 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
130 memcpy(emac->addr, addr, 6);
131 emac_hal_set_address(&emac->hal, emac->addr);
132 return ESP_OK;
133 err:
134 return ret;
135 }
136
emac_esp32_get_addr(esp_eth_mac_t * mac,uint8_t * addr)137 static esp_err_t emac_esp32_get_addr(esp_eth_mac_t *mac, uint8_t *addr)
138 {
139 esp_err_t ret = ESP_OK;
140 ESP_GOTO_ON_FALSE(addr, ESP_ERR_INVALID_ARG, err, TAG, "can't set mac addr to null");
141 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
142 memcpy(addr, emac->addr, 6);
143 return ESP_OK;
144 err:
145 return ret;
146 }
147
emac_esp32_set_link(esp_eth_mac_t * mac,eth_link_t link)148 static esp_err_t emac_esp32_set_link(esp_eth_mac_t *mac, eth_link_t link)
149 {
150 esp_err_t ret = ESP_OK;
151 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
152 switch (link) {
153 case ETH_LINK_UP:
154 ESP_GOTO_ON_ERROR(esp_intr_enable(emac->intr_hdl), err, TAG, "enable interrupt failed");
155 emac_esp32_start(mac);
156 break;
157 case ETH_LINK_DOWN:
158 ESP_GOTO_ON_ERROR(esp_intr_disable(emac->intr_hdl), err, TAG, "disable interrupt failed");
159 emac_esp32_stop(mac);
160 break;
161 default:
162 ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "unknown link status");
163 break;
164 }
165 return ESP_OK;
166 err:
167 return ret;
168 }
169
emac_esp32_set_speed(esp_eth_mac_t * mac,eth_speed_t speed)170 static esp_err_t emac_esp32_set_speed(esp_eth_mac_t *mac, eth_speed_t speed)
171 {
172 esp_err_t ret = ESP_ERR_INVALID_ARG;
173 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
174 if (speed >= ETH_SPEED_10M && speed < ETH_SPEED_MAX) {
175 emac_ll_set_port_speed(emac->hal.mac_regs, speed);
176 ESP_LOGD(TAG, "working in %dMbps", speed == ETH_SPEED_10M ? 10 : 100);
177 return ESP_OK;
178 }
179 return ret;
180 }
181
emac_esp32_set_duplex(esp_eth_mac_t * mac,eth_duplex_t duplex)182 static esp_err_t emac_esp32_set_duplex(esp_eth_mac_t *mac, eth_duplex_t duplex)
183 {
184 esp_err_t ret = ESP_ERR_INVALID_ARG;
185 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
186 if (duplex == ETH_DUPLEX_HALF || duplex == ETH_DUPLEX_FULL) {
187 emac_ll_set_duplex(emac->hal.mac_regs, duplex);
188 ESP_LOGD(TAG, "working in %s duplex", duplex == ETH_DUPLEX_HALF ? "half" : "full");
189 return ESP_OK;
190 }
191 return ret;
192 }
193
emac_esp32_set_promiscuous(esp_eth_mac_t * mac,bool enable)194 static esp_err_t emac_esp32_set_promiscuous(esp_eth_mac_t *mac, bool enable)
195 {
196 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
197 emac_ll_promiscuous_mode_enable(emac->hal.mac_regs, enable);
198 return ESP_OK;
199 }
200
emac_esp32_enable_flow_ctrl(esp_eth_mac_t * mac,bool enable)201 static esp_err_t emac_esp32_enable_flow_ctrl(esp_eth_mac_t *mac, bool enable)
202 {
203 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
204 emac->flow_ctrl_enabled = enable;
205 return ESP_OK;
206 }
207
emac_esp32_set_peer_pause_ability(esp_eth_mac_t * mac,uint32_t ability)208 static esp_err_t emac_esp32_set_peer_pause_ability(esp_eth_mac_t *mac, uint32_t ability)
209 {
210 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
211 // we want to enable flow control, and peer does support pause function
212 // then configure the MAC layer to enable flow control feature
213 if (emac->flow_ctrl_enabled && ability) {
214 emac_hal_enable_flow_ctrl(&emac->hal, true);
215 emac->do_flow_ctrl = true;
216 } else {
217 emac_hal_enable_flow_ctrl(&emac->hal, false);
218 emac->do_flow_ctrl = false;
219 ESP_LOGD(TAG, "Flow control not enabled for the link");
220 }
221 return ESP_OK;
222 }
223
emac_esp32_transmit(esp_eth_mac_t * mac,uint8_t * buf,uint32_t length)224 static esp_err_t emac_esp32_transmit(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length)
225 {
226 esp_err_t ret = ESP_OK;
227 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
228 uint32_t sent_len = emac_hal_transmit_frame(&emac->hal, buf, length);
229 ESP_GOTO_ON_FALSE(sent_len == length, ESP_ERR_NO_MEM, err, TAG, "insufficient TX buffer size");
230 return ESP_OK;
231 err:
232 return ret;
233 }
234
emac_esp32_receive(esp_eth_mac_t * mac,uint8_t * buf,uint32_t * length)235 static esp_err_t emac_esp32_receive(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length)
236 {
237 esp_err_t ret = ESP_OK;
238 uint32_t expected_len = *length;
239 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
240 ESP_GOTO_ON_FALSE(buf && length, ESP_ERR_INVALID_ARG, err, TAG, "can't set buf and length to null");
241 uint32_t receive_len = emac_hal_receive_frame(&emac->hal, buf, expected_len, &emac->frames_remain, &emac->free_rx_descriptor);
242 /* we need to check the return value in case the buffer size is not enough */
243 ESP_LOGD(TAG, "receive len= %d", receive_len);
244 ESP_GOTO_ON_FALSE(expected_len >= receive_len, ESP_ERR_INVALID_SIZE, err, TAG, "received buffer longer than expected");
245 *length = receive_len;
246 return ESP_OK;
247 err:
248 *length = expected_len;
249 return ret;
250 }
251
emac_esp32_rx_task(void * arg)252 static void emac_esp32_rx_task(void *arg)
253 {
254 emac_esp32_t *emac = (emac_esp32_t *)arg;
255 uint8_t *buffer = NULL;
256 uint32_t length = 0;
257 while (1) {
258 // block indefinitely until got notification from underlay event
259 ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
260 do {
261 length = ETH_MAX_PACKET_SIZE;
262 buffer = malloc(length);
263 if (!buffer) {
264 ESP_LOGE(TAG, "no mem for receive buffer");
265 } else if (emac_esp32_receive(&emac->parent, buffer, &length) == ESP_OK) {
266 /* pass the buffer to stack (e.g. TCP/IP layer) */
267 if (length) {
268 emac->eth->stack_input(emac->eth, buffer, length);
269 } else {
270 free(buffer);
271 }
272 } else {
273 free(buffer);
274 }
275 #if CONFIG_ETH_SOFT_FLOW_CONTROL
276 // we need to do extra checking of remained frames in case there are no unhandled frames left, but pause frame is still undergoing
277 if ((emac->free_rx_descriptor < emac->flow_control_low_water_mark) && emac->do_flow_ctrl && emac->frames_remain) {
278 emac_ll_pause_frame_enable(emac->hal.ext_regs, true);
279 } else if ((emac->free_rx_descriptor > emac->flow_control_high_water_mark) || !emac->frames_remain) {
280 emac_ll_pause_frame_enable(emac->hal.ext_regs, false);
281 }
282 #endif
283 } while (emac->frames_remain);
284 }
285 vTaskDelete(NULL);
286 }
287
emac_esp32_init_smi_gpio(emac_esp32_t * emac)288 static void emac_esp32_init_smi_gpio(emac_esp32_t *emac)
289 {
290 if (emac->smi_mdc_gpio_num >= 0) {
291 /* Setup SMI MDC GPIO */
292 gpio_set_direction(emac->smi_mdc_gpio_num, GPIO_MODE_OUTPUT);
293 esp_rom_gpio_connect_out_signal(emac->smi_mdc_gpio_num, EMAC_MDC_O_IDX, false, false);
294 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[emac->smi_mdc_gpio_num], PIN_FUNC_GPIO);
295 }
296 if (emac->smi_mdio_gpio_num >= 0) {
297 /* Setup SMI MDIO GPIO */
298 gpio_set_direction(emac->smi_mdio_gpio_num, GPIO_MODE_INPUT_OUTPUT);
299 esp_rom_gpio_connect_out_signal(emac->smi_mdio_gpio_num, EMAC_MDO_O_IDX, false, false);
300 esp_rom_gpio_connect_in_signal(emac->smi_mdio_gpio_num, EMAC_MDI_I_IDX, false);
301 gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[emac->smi_mdio_gpio_num], PIN_FUNC_GPIO);
302 }
303 }
304
emac_config_apll_clock(void)305 static void emac_config_apll_clock(void)
306 {
307 /* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2) */
308 rtc_xtal_freq_t rtc_xtal_freq = rtc_clk_xtal_freq_get();
309 switch (rtc_xtal_freq) {
310 case RTC_XTAL_FREQ_40M: // Recommended
311 /* 50 MHz = 40MHz * (4 + 6) / (2 * (2 + 2) = 50.000 */
312 /* sdm0 = 0, sdm1 = 0, sdm2 = 6, o_div = 2 */
313 rtc_clk_apll_enable(true, 0, 0, 6, 2);
314 break;
315 case RTC_XTAL_FREQ_26M:
316 /* 50 MHz = 26MHz * (4 + 15 + 118 / 256 + 39/65536) / ((3 + 2) * 2) = 49.999992 */
317 /* sdm0 = 39, sdm1 = 118, sdm2 = 15, o_div = 3 */
318 rtc_clk_apll_enable(true, 39, 118, 15, 3);
319 break;
320 case RTC_XTAL_FREQ_24M:
321 /* 50 MHz = 24MHz * (4 + 12 + 255 / 256 + 255/65536) / ((2 + 2) * 2) = 49.499977 */
322 /* sdm0 = 255, sdm1 = 255, sdm2 = 12, o_div = 2 */
323 rtc_clk_apll_enable(true, 255, 255, 12, 2);
324 break;
325 default: // Assume we have a 40M xtal
326 rtc_clk_apll_enable(true, 0, 0, 6, 2);
327 break;
328 }
329 }
330
emac_esp32_init(esp_eth_mac_t * mac)331 static esp_err_t emac_esp32_init(esp_eth_mac_t *mac)
332 {
333 esp_err_t ret = ESP_OK;
334 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
335 esp_eth_mediator_t *eth = emac->eth;
336
337 /* init gpio used by smi interface */
338 emac_esp32_init_smi_gpio(emac);
339 ESP_GOTO_ON_ERROR(eth->on_state_changed(eth, ETH_STATE_LLINIT, NULL), err, TAG, "lowlevel init failed");
340 /* software reset */
341 emac_ll_reset(emac->hal.dma_regs);
342 uint32_t to = 0;
343 for (to = 0; to < emac->sw_reset_timeout_ms / 10; to++) {
344 if (emac_ll_is_reset_done(emac->hal.dma_regs)) {
345 break;
346 }
347 vTaskDelay(pdMS_TO_TICKS(10));
348 }
349 ESP_GOTO_ON_FALSE(to < emac->sw_reset_timeout_ms / 10, ESP_ERR_TIMEOUT, err, TAG, "reset timeout");
350 /* set smi clock */
351 emac_hal_set_csr_clock_range(&emac->hal, esp_clk_apb_freq());
352 /* reset descriptor chain */
353 emac_hal_reset_desc_chain(&emac->hal);
354 /* init mac registers by default */
355 emac_hal_init_mac_default(&emac->hal);
356 /* init dma registers by default */
357 emac_hal_init_dma_default(&emac->hal);
358 /* get emac address from efuse */
359 ESP_GOTO_ON_ERROR(esp_read_mac(emac->addr, ESP_MAC_ETH), err, TAG, "fetch ethernet mac address failed");
360 /* set MAC address to emac register */
361 emac_hal_set_address(&emac->hal, emac->addr);
362 #ifdef CONFIG_PM_ENABLE
363 esp_pm_lock_acquire(emac->pm_lock);
364 #endif
365 return ESP_OK;
366 err:
367 eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
368 periph_module_disable(PERIPH_EMAC_MODULE);
369 return ret;
370 }
371
emac_esp32_deinit(esp_eth_mac_t * mac)372 static esp_err_t emac_esp32_deinit(esp_eth_mac_t *mac)
373 {
374 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
375 esp_eth_mediator_t *eth = emac->eth;
376 #ifdef CONFIG_PM_ENABLE
377 esp_pm_lock_release(emac->pm_lock);
378 #endif
379 emac_hal_stop(&emac->hal);
380 eth->on_state_changed(eth, ETH_STATE_DEINIT, NULL);
381 return ESP_OK;
382 }
383
emac_esp32_start(esp_eth_mac_t * mac)384 static esp_err_t emac_esp32_start(esp_eth_mac_t *mac)
385 {
386 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
387 emac_hal_reset_desc_chain(&emac->hal);
388 emac_hal_start(&emac->hal);
389 return ESP_OK;
390 }
391
emac_esp32_stop(esp_eth_mac_t * mac)392 static esp_err_t emac_esp32_stop(esp_eth_mac_t *mac)
393 {
394 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
395 esp_err_t ret = ESP_OK;
396 int32_t to = 0;
397 do {
398 if ((ret = emac_hal_stop(&emac->hal)) == ESP_OK) {
399 break;
400 }
401 to += 25;
402 esp_rom_delay_us(25);
403 } while (to < MAC_STOP_TIMEOUT_US);
404 return ret;
405 }
406
emac_esp32_del(esp_eth_mac_t * mac)407 static esp_err_t emac_esp32_del(esp_eth_mac_t *mac)
408 {
409 emac_esp32_t *emac = __containerof(mac, emac_esp32_t, parent);
410 esp_emac_free_driver_obj(emac, emac->hal.descriptors);
411 periph_module_disable(PERIPH_EMAC_MODULE);
412 return ESP_OK;
413 }
414
415 // To achieve a better performance, we put the ISR always in IRAM
emac_isr_default_handler(void * args)416 IRAM_ATTR void emac_isr_default_handler(void *args)
417 {
418 emac_hal_context_t *hal = (emac_hal_context_t *)args;
419 emac_esp32_t *emac = __containerof(hal, emac_esp32_t, hal);
420 BaseType_t high_task_wakeup = pdFALSE;
421 uint32_t intr_stat = emac_ll_get_intr_status(hal->dma_regs);
422 emac_ll_clear_corresponding_intr(hal->dma_regs, intr_stat);
423
424 #if EMAC_LL_CONFIG_ENABLE_INTR_MASK & EMAC_LL_INTR_RECEIVE_ENABLE
425 if (intr_stat & EMAC_LL_DMA_RECEIVE_FINISH_INTR) {
426 /* notify receive task */
427 vTaskNotifyGiveFromISR(emac->rx_task_hdl, &high_task_wakeup);
428 if (high_task_wakeup == pdTRUE) {
429 portYIELD_FROM_ISR();
430 }
431 }
432 #endif
433 }
434
esp_emac_free_driver_obj(emac_esp32_t * emac,void * descriptors)435 static void esp_emac_free_driver_obj(emac_esp32_t *emac, void *descriptors)
436 {
437 if (emac) {
438 if (emac->rx_task_hdl) {
439 vTaskDelete(emac->rx_task_hdl);
440 }
441 if (emac->intr_hdl) {
442 esp_intr_free(emac->intr_hdl);
443 }
444 for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
445 free(emac->tx_buf[i]);
446 }
447 for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
448 free(emac->rx_buf[i]);
449 }
450 #ifdef CONFIG_PM_ENABLE
451 if (emac->pm_lock) {
452 esp_pm_lock_delete(emac->pm_lock);
453 }
454 #endif
455 free(emac);
456 }
457 if (descriptors) {
458 free(descriptors);
459 }
460 }
461
esp_emac_alloc_driver_obj(const eth_mac_config_t * config,emac_esp32_t ** emac_out_hdl,void ** out_descriptors)462 static esp_err_t esp_emac_alloc_driver_obj(const eth_mac_config_t *config, emac_esp32_t **emac_out_hdl, void **out_descriptors)
463 {
464 esp_err_t ret = ESP_OK;
465 emac_esp32_t *emac = NULL;
466 void *descriptors = NULL;
467 if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
468 emac = heap_caps_calloc(1, sizeof(emac_esp32_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
469 } else {
470 emac = calloc(1, sizeof(emac_esp32_t));
471 }
472 ESP_GOTO_ON_FALSE(emac, ESP_ERR_NO_MEM, err, TAG, "no mem for esp emac object");
473 /* alloc memory for ethernet dma descriptor */
474 uint32_t desc_size = CONFIG_ETH_DMA_RX_BUFFER_NUM * sizeof(eth_dma_rx_descriptor_t) +
475 CONFIG_ETH_DMA_TX_BUFFER_NUM * sizeof(eth_dma_tx_descriptor_t);
476 descriptors = heap_caps_calloc(1, desc_size, MALLOC_CAP_DMA);
477 ESP_GOTO_ON_FALSE(descriptors, ESP_ERR_NO_MEM, err, TAG, "no mem for descriptors");
478 /* alloc memory for ethernet dma buffer */
479 for (int i = 0; i < CONFIG_ETH_DMA_RX_BUFFER_NUM; i++) {
480 emac->rx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
481 ESP_GOTO_ON_FALSE(emac->rx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for RX DMA buffers");
482 }
483 for (int i = 0; i < CONFIG_ETH_DMA_TX_BUFFER_NUM; i++) {
484 emac->tx_buf[i] = heap_caps_calloc(1, CONFIG_ETH_DMA_BUFFER_SIZE, MALLOC_CAP_DMA);
485 ESP_GOTO_ON_FALSE(emac->tx_buf[i], ESP_ERR_NO_MEM, err, TAG, "no mem for TX DMA buffers");
486 }
487 /* alloc PM lock */
488 #ifdef CONFIG_PM_ENABLE
489 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");
490 #endif
491 /* create rx task */
492 BaseType_t core_num = tskNO_AFFINITY;
493 if (config->flags & ETH_MAC_FLAG_PIN_TO_CORE) {
494 core_num = cpu_hal_get_core_id();
495 }
496 BaseType_t xReturned = xTaskCreatePinnedToCore(emac_esp32_rx_task, "emac_rx", config->rx_task_stack_size, emac,
497 config->rx_task_prio, &emac->rx_task_hdl, core_num);
498 ESP_GOTO_ON_FALSE(xReturned == pdPASS, ESP_FAIL, err, TAG, "create emac_rx task failed");
499
500 *out_descriptors = descriptors;
501 *emac_out_hdl = emac;
502 return ESP_OK;
503 err:
504 esp_emac_free_driver_obj(emac, descriptors);
505 return ret;
506 }
507
esp_emac_config_data_interface(const eth_mac_config_t * config,emac_esp32_t * emac)508 static esp_err_t esp_emac_config_data_interface(const eth_mac_config_t *config, emac_esp32_t *emac)
509 {
510 esp_err_t ret = ESP_OK;
511 switch (config->interface) {
512 case EMAC_DATA_INTERFACE_MII:
513 emac->clock_config = config->clock_config;
514 /* MII interface GPIO initialization */
515 emac_hal_iomux_init_mii();
516 /* Enable MII clock */
517 emac_ll_clock_enable_mii(emac->hal.ext_regs);
518 break;
519 case EMAC_DATA_INTERFACE_RMII:
520 // by default, the clock mode is selected at compile time (by Kconfig)
521 if (config->clock_config.rmii.clock_mode == EMAC_CLK_DEFAULT) {
522 #if CONFIG_ETH_RMII_CLK_INPUT
523 #if CONFIG_ETH_RMII_CLK_IN_GPIO == 0
524 emac->clock_config.rmii.clock_mode = EMAC_CLK_EXT_IN;
525 emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_IN_GPIO;
526 #else
527 #error "ESP32 EMAC only support input RMII clock to GPIO0"
528 #endif // CONFIG_ETH_RMII_CLK_IN_GPIO == 0
529 #elif CONFIG_ETH_RMII_CLK_OUTPUT
530 emac->clock_config.rmii.clock_mode = EMAC_CLK_OUT;
531 #if CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
532 emac->clock_config.rmii.clock_gpio = 0;
533 #elif CONFIG_ETH_RMII_CLK_OUT_GPIO
534 emac->clock_config.rmii.clock_gpio = CONFIG_ETH_RMII_CLK_OUT_GPIO;
535 #endif // CONFIG_ETH_RMII_CLK_OUTPUT_GPIO0
536 #else
537 #error "Unsupported RMII clock mode"
538 #endif
539 } else {
540 emac->clock_config = config->clock_config;
541 }
542 /* RMII interface GPIO initialization */
543 emac_hal_iomux_init_rmii();
544 /* If ref_clk is configured as input */
545 if (emac->clock_config.rmii.clock_mode == EMAC_CLK_EXT_IN) {
546 ESP_GOTO_ON_FALSE(emac->clock_config.rmii.clock_gpio == EMAC_CLK_IN_GPIO,
547 ESP_ERR_INVALID_ARG, err, TAG, "ESP32 EMAC only support input RMII clock to GPIO0");
548 emac_hal_iomux_rmii_clk_input();
549 emac_ll_clock_enable_rmii_input(emac->hal.ext_regs);
550 } else if (emac->clock_config.rmii.clock_mode == EMAC_CLK_OUT) {
551 ESP_GOTO_ON_FALSE(emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO ||
552 emac->clock_config.rmii.clock_gpio == EMAC_CLK_OUT_GPIO ||
553 emac->clock_config.rmii.clock_gpio == EMAC_CLK_OUT_180_GPIO,
554 ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock output GPIO");
555 emac_hal_iomux_rmii_clk_ouput(emac->clock_config.rmii.clock_gpio);
556 if (emac->clock_config.rmii.clock_gpio == EMAC_APPL_CLK_OUT_GPIO) {
557 REG_SET_FIELD(PIN_CTRL, CLK_OUT1, 6);
558 }
559 /* Enable RMII clock */
560 emac_ll_clock_enable_rmii_output(emac->hal.ext_regs);
561 emac_config_apll_clock();
562 } else {
563 ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC clock mode");
564 }
565 break;
566 default:
567 ESP_GOTO_ON_FALSE(false, ESP_ERR_INVALID_ARG, err, TAG, "invalid EMAC Data Interface:%d", config->interface);
568 }
569 err:
570 return ret;
571 }
572
esp_eth_mac_new_esp32(const eth_mac_config_t * config)573 esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config)
574 {
575 esp_err_t ret_code = ESP_OK;
576 esp_eth_mac_t *ret = NULL;
577 void *descriptors = NULL;
578 emac_esp32_t *emac = NULL;
579 ESP_GOTO_ON_FALSE(config, NULL, err, TAG, "can't set mac config to null");
580 ret_code = esp_emac_alloc_driver_obj(config, &emac, &descriptors);
581 ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc driver object failed");
582
583 /* enable APB to access Ethernet peripheral registers */
584 periph_module_enable(PERIPH_EMAC_MODULE);
585 /* initialize hal layer driver */
586 emac_hal_init(&emac->hal, descriptors, emac->rx_buf, emac->tx_buf);
587 /* alloc interrupt */
588 if (config->flags & ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE) {
589 ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, ESP_INTR_FLAG_IRAM,
590 emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
591 } else {
592 ret_code = esp_intr_alloc(ETS_ETH_MAC_INTR_SOURCE, 0,
593 emac_isr_default_handler, &emac->hal, &(emac->intr_hdl));
594 }
595 ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err, TAG, "alloc emac interrupt failed");
596 ret_code = esp_emac_config_data_interface(config, emac);
597 ESP_GOTO_ON_FALSE(ret_code == ESP_OK, NULL, err_interf, TAG, "config emac interface failed");
598
599 emac->sw_reset_timeout_ms = config->sw_reset_timeout_ms;
600 emac->smi_mdc_gpio_num = config->smi_mdc_gpio_num;
601 emac->smi_mdio_gpio_num = config->smi_mdio_gpio_num;
602 emac->flow_control_high_water_mark = FLOW_CONTROL_HIGH_WATER_MARK;
603 emac->flow_control_low_water_mark = FLOW_CONTROL_LOW_WATER_MARK;
604 emac->parent.set_mediator = emac_esp32_set_mediator;
605 emac->parent.init = emac_esp32_init;
606 emac->parent.deinit = emac_esp32_deinit;
607 emac->parent.start = emac_esp32_start;
608 emac->parent.stop = emac_esp32_stop;
609 emac->parent.del = emac_esp32_del;
610 emac->parent.write_phy_reg = emac_esp32_write_phy_reg;
611 emac->parent.read_phy_reg = emac_esp32_read_phy_reg;
612 emac->parent.set_addr = emac_esp32_set_addr;
613 emac->parent.get_addr = emac_esp32_get_addr;
614 emac->parent.set_speed = emac_esp32_set_speed;
615 emac->parent.set_duplex = emac_esp32_set_duplex;
616 emac->parent.set_link = emac_esp32_set_link;
617 emac->parent.set_promiscuous = emac_esp32_set_promiscuous;
618 emac->parent.set_peer_pause_ability = emac_esp32_set_peer_pause_ability;
619 emac->parent.enable_flow_ctrl = emac_esp32_enable_flow_ctrl;
620 emac->parent.transmit = emac_esp32_transmit;
621 emac->parent.receive = emac_esp32_receive;
622 return &(emac->parent);
623
624 err_interf:
625 periph_module_disable(PERIPH_EMAC_MODULE);
626 err:
627 esp_emac_free_driver_obj(emac, descriptors);
628 return ret;
629 }
630