1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #pragma once
15 
16 #include <stdbool.h>
17 #include "esp_eth_com.h"
18 #include "sdkconfig.h"
19 
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23 
24 /**
25 * @brief Ethernet MAC
26 *
27 */
28 typedef struct esp_eth_mac_s esp_eth_mac_t;
29 
30 /**
31 * @brief Ethernet MAC
32 *
33 */
34 struct esp_eth_mac_s {
35     /**
36     * @brief Set mediator for Ethernet MAC
37     *
38     * @param[in] mac: Ethernet MAC instance
39     * @param[in] eth: Ethernet mediator
40     *
41     * @return
42     *      - ESP_OK: set mediator for Ethernet MAC successfully
43     *      - ESP_ERR_INVALID_ARG: set mediator for Ethernet MAC failed because of invalid argument
44     *
45     */
46     esp_err_t (*set_mediator)(esp_eth_mac_t *mac, esp_eth_mediator_t *eth);
47 
48     /**
49     * @brief Initialize Ethernet MAC
50     *
51     * @param[in] mac: Ethernet MAC instance
52     *
53     * @return
54     *      - ESP_OK: initialize Ethernet MAC successfully
55     *      - ESP_ERR_TIMEOUT: initialize Ethernet MAC failed because of timeout
56     *      - ESP_FAIL: initialize Ethernet MAC failed because some other error occurred
57     *
58     */
59     esp_err_t (*init)(esp_eth_mac_t *mac);
60 
61     /**
62     * @brief Deinitialize Ethernet MAC
63     *
64     * @param[in] mac: Ethernet MAC instance
65     *
66     * @return
67     *      - ESP_OK: deinitialize Ethernet MAC successfully
68     *      - ESP_FAIL: deinitialize Ethernet MAC failed because some error occurred
69     *
70     */
71     esp_err_t (*deinit)(esp_eth_mac_t *mac);
72 
73     /**
74     * @brief Start Ethernet MAC
75     *
76     * @param[in] mac: Ethernet MAC instance
77     *
78     * @return
79     *      - ESP_OK: start Ethernet MAC successfully
80     *      - ESP_FAIL: start Ethernet MAC failed because some other error occurred
81     *
82     */
83     esp_err_t (*start)(esp_eth_mac_t *mac);
84 
85     /**
86     * @brief Stop Ethernet MAC
87     *
88     * @param[in] mac: Ethernet MAC instance
89     *
90     * @return
91     *      - ESP_OK: stop Ethernet MAC successfully
92     *      - ESP_FAIL: stop Ethernet MAC failed because some error occurred
93     *
94     */
95     esp_err_t (*stop)(esp_eth_mac_t *mac);
96 
97     /**
98     * @brief Transmit packet from Ethernet MAC
99     *
100     * @param[in] mac: Ethernet MAC instance
101     * @param[in] buf: packet buffer to transmit
102     * @param[in] length: length of packet
103     *
104     * @return
105     *      - ESP_OK: transmit packet successfully
106     *      - ESP_ERR_INVALID_ARG: transmit packet failed because of invalid argument
107     *      - ESP_ERR_INVALID_STATE: transmit packet failed because of wrong state of MAC
108     *      - ESP_FAIL: transmit packet failed because some other error occurred
109     *
110     */
111     esp_err_t (*transmit)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t length);
112 
113     /**
114     * @brief Receive packet from Ethernet MAC
115     *
116     * @param[in] mac: Ethernet MAC instance
117     * @param[out] buf: packet buffer which will preserve the received frame
118     * @param[out] length: length of the received packet
119     *
120     * @note Memory of buf is allocated in the Layer2, make sure it get free after process.
121     * @note Before this function got invoked, the value of "length" should set by user, equals the size of buffer.
122     *       After the function returned, the value of "length" means the real length of received data.
123     *
124     * @return
125     *      - ESP_OK: receive packet successfully
126     *      - ESP_ERR_INVALID_ARG: receive packet failed because of invalid argument
127     *      - ESP_ERR_INVALID_SIZE: input buffer size is not enough to hold the incoming data.
128     *                              in this case, value of returned "length" indicates the real size of incoming data.
129     *      - ESP_FAIL: receive packet failed because some other error occurred
130     *
131     */
132     esp_err_t (*receive)(esp_eth_mac_t *mac, uint8_t *buf, uint32_t *length);
133 
134     /**
135     * @brief Read PHY register
136     *
137     * @param[in] mac: Ethernet MAC instance
138     * @param[in] phy_addr: PHY chip address (0~31)
139     * @param[in] phy_reg: PHY register index code
140     * @param[out] reg_value: PHY register value
141     *
142     * @return
143     *      - ESP_OK: read PHY register successfully
144     *      - ESP_ERR_INVALID_ARG: read PHY register failed because of invalid argument
145     *      - ESP_ERR_INVALID_STATE: read PHY register failed because of wrong state of MAC
146     *      - ESP_ERR_TIMEOUT: read PHY register failed because of timeout
147     *      - ESP_FAIL: read PHY register failed because some other error occurred
148     *
149     */
150     esp_err_t (*read_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t *reg_value);
151 
152     /**
153     * @brief Write PHY register
154     *
155     * @param[in] mac: Ethernet MAC instance
156     * @param[in] phy_addr: PHY chip address (0~31)
157     * @param[in] phy_reg: PHY register index code
158     * @param[in] reg_value: PHY register value
159     *
160     * @return
161     *      - ESP_OK: write PHY register successfully
162     *      - ESP_ERR_INVALID_STATE: write PHY register failed because of wrong state of MAC
163     *      - ESP_ERR_TIMEOUT: write PHY register failed because of timeout
164     *      - ESP_FAIL: write PHY register failed because some other error occurred
165     *
166     */
167     esp_err_t (*write_phy_reg)(esp_eth_mac_t *mac, uint32_t phy_addr, uint32_t phy_reg, uint32_t reg_value);
168 
169     /**
170     * @brief Set MAC address
171     *
172     * @param[in] mac: Ethernet MAC instance
173     * @param[in] addr: MAC address
174     *
175     * @return
176     *      - ESP_OK: set MAC address successfully
177     *      - ESP_ERR_INVALID_ARG: set MAC address failed because of invalid argument
178     *      - ESP_FAIL: set MAC address failed because some other error occurred
179     *
180     */
181     esp_err_t (*set_addr)(esp_eth_mac_t *mac, uint8_t *addr);
182 
183     /**
184     * @brief Get MAC address
185     *
186     * @param[in] mac: Ethernet MAC instance
187     * @param[out] addr: MAC address
188     *
189     * @return
190     *      - ESP_OK: get MAC address successfully
191     *      - ESP_ERR_INVALID_ARG: get MAC address failed because of invalid argument
192     *      - ESP_FAIL: get MAC address failed because some other error occurred
193     *
194     */
195     esp_err_t (*get_addr)(esp_eth_mac_t *mac, uint8_t *addr);
196 
197     /**
198     * @brief Set speed of MAC
199     *
200     * @param[in] ma:c Ethernet MAC instance
201     * @param[in] speed: MAC speed
202     *
203     * @return
204     *      - ESP_OK: set MAC speed successfully
205     *      - ESP_ERR_INVALID_ARG: set MAC speed failed because of invalid argument
206     *      - ESP_FAIL: set MAC speed failed because some other error occurred
207     *
208     */
209     esp_err_t (*set_speed)(esp_eth_mac_t *mac, eth_speed_t speed);
210 
211     /**
212     * @brief Set duplex mode of MAC
213     *
214     * @param[in] mac: Ethernet MAC instance
215     * @param[in] duplex: MAC duplex
216     *
217     * @return
218     *      - ESP_OK: set MAC duplex mode successfully
219     *      - ESP_ERR_INVALID_ARG: set MAC duplex failed because of invalid argument
220     *      - ESP_FAIL: set MAC duplex failed because some other error occurred
221     *
222     */
223     esp_err_t (*set_duplex)(esp_eth_mac_t *mac, eth_duplex_t duplex);
224 
225     /**
226     * @brief Set link status of MAC
227     *
228     * @param[in] mac: Ethernet MAC instance
229     * @param[in] link: Link status
230     *
231     * @return
232     *      - ESP_OK: set link status successfully
233     *      - ESP_ERR_INVALID_ARG: set link status failed because of invalid argument
234     *      - ESP_FAIL: set link status failed because some other error occurred
235     *
236     */
237     esp_err_t (*set_link)(esp_eth_mac_t *mac, eth_link_t link);
238 
239     /**
240     * @brief Set promiscuous of MAC
241     *
242     * @param[in] mac: Ethernet MAC instance
243     * @param[in] enable: set true to enable promiscuous mode; set false to disable promiscuous mode
244     *
245     * @return
246     *      - ESP_OK: set promiscuous mode successfully
247     *      - ESP_FAIL: set promiscuous mode failed because some error occurred
248     *
249     */
250     esp_err_t (*set_promiscuous)(esp_eth_mac_t *mac, bool enable);
251 
252     /**
253     * @brief Enable flow control on MAC layer or not
254     *
255     * @param[in] mac: Ethernet MAC instance
256     * @param[in] enable: set true to enable flow control; set false to disable flow control
257     *
258     * @return
259     *      - ESP_OK: set flow control successfully
260     *      - ESP_FAIL: set flow control failed because some error occurred
261     *
262     */
263     esp_err_t (*enable_flow_ctrl)(esp_eth_mac_t *mac, bool enable);
264 
265     /**
266     * @brief Set the PAUSE ability of peer node
267     *
268     * @param[in] mac: Ethernet MAC instance
269     * @param[in] ability: zero indicates that pause function is supported by link partner; non-zero indicates that pause function is not supported by link partner
270     *
271     * @return
272     *      - ESP_OK: set peer pause ability successfully
273     *      - ESP_FAIL: set peer pause ability failed because some error occurred
274     */
275     esp_err_t (*set_peer_pause_ability)(esp_eth_mac_t *mac, uint32_t ability);
276 
277     /**
278     * @brief Free memory of Ethernet MAC
279     *
280     * @param[in] mac: Ethernet MAC instance
281     *
282     * @return
283     *      - ESP_OK: free Ethernet MAC instance successfully
284     *      - ESP_FAIL: free Ethernet MAC instance failed because some error occurred
285     *
286     */
287     esp_err_t (*del)(esp_eth_mac_t *mac);
288 };
289 
290 /**
291  * @brief RMII Clock Mode Options
292  *
293  */
294 typedef enum {
295     /**
296      * @brief Default values configured using Kconfig are going to be used when "Default" selected.
297      *
298      */
299     EMAC_CLK_DEFAULT,
300 
301     /**
302      * @brief Input RMII Clock from external. EMAC Clock GPIO number needs to be configured when this option is selected.
303      *
304      * @note MAC will get RMII clock from outside. Note that ESP32 only supports GPIO0 to input the RMII clock.
305      *
306      */
307     EMAC_CLK_EXT_IN,
308 
309     /**
310      * @brief Output RMII Clock from internal APLL Clock. EMAC Clock GPIO number needs to be configured when this option is selected.
311      *
312      */
313     EMAC_CLK_OUT
314 } emac_rmii_clock_mode_t;
315 
316 /**
317  * @brief RMII Clock GPIO number Options
318  *
319  */
320 typedef enum {
321     /**
322      * @brief MAC will get RMII clock from outside at this GPIO.
323      *
324      * @note ESP32 only supports GPIO0 to input the RMII clock.
325      *
326      */
327     EMAC_CLK_IN_GPIO = 0,
328 
329     /**
330      * @brief Output RMII Clock from internal APLL Clock available at GPIO0
331      *
332      * @note GPIO0 can be set to output a pre-divided PLL clock (test only!). Enabling this option will configure GPIO0 to output a 50MHz clock.
333      * In fact this clock doesn’t have directly relationship with EMAC peripheral. Sometimes this clock won’t work well with your PHY chip.
334      * You might need to add some extra devices after GPIO0 (e.g. inverter). Note that outputting RMII clock on GPIO0 is an experimental practice.
335      * If you want the Ethernet to work with WiFi, don’t select GPIO0 output mode for stability.
336      *
337      */
338     EMAC_APPL_CLK_OUT_GPIO = 0,
339 
340     /**
341      * @brief Output RMII Clock from internal APLL Clock available at GPIO16
342      *
343      */
344     EMAC_CLK_OUT_GPIO = 16,
345 
346     /**
347      * @brief Inverted Output RMII Clock from internal APLL Clock available at GPIO17
348      *
349      */
350     EMAC_CLK_OUT_180_GPIO = 17
351 } emac_rmii_clock_gpio_t;
352 
353 /**
354  * @brief Ethernet MAC Clock Configuration
355  *
356  */
357 typedef union {
358     struct {
359         // MII interface is not fully implemented...
360         // Reserved for GPIO number, clock source, etc. in MII mode
361     } mii; /*!< EMAC MII Clock Configuration */
362     struct {
363         emac_rmii_clock_mode_t clock_mode; /*!< RMII Clock Mode Configuration */
364         emac_rmii_clock_gpio_t clock_gpio; /*!< RMII Clock GPIO Configuration */
365     } rmii; /*!< EMAC RMII Clock Configuration */
366 } eth_mac_clock_config_t;
367 
368 
369 /**
370 * @brief Configuration of Ethernet MAC object
371 *
372 */
373 typedef struct {
374     uint32_t sw_reset_timeout_ms;        /*!< Software reset timeout value (Unit: ms) */
375     uint32_t rx_task_stack_size;         /*!< Stack size of the receive task */
376     uint32_t rx_task_prio;               /*!< Priority of the receive task */
377     int smi_mdc_gpio_num;                /*!< SMI MDC GPIO number, set to -1 could bypass the SMI GPIO configuration */
378     int smi_mdio_gpio_num;               /*!< SMI MDIO GPIO number, set to -1 could bypass the SMI GPIO configuration */
379     uint32_t flags;                      /*!< Flags that specify extra capability for mac driver */
380     eth_data_interface_t interface;      /*!< EMAC Data interface to PHY (MII/RMII) */
381     eth_mac_clock_config_t clock_config; /*!< EMAC Interface clock configuration */
382 } eth_mac_config_t;
383 
384 #define ETH_MAC_FLAG_WORK_WITH_CACHE_DISABLE (1 << 0) /*!< MAC driver can work when cache is disabled */
385 #define ETH_MAC_FLAG_PIN_TO_CORE (1 << 1)             /*!< Pin MAC task to the CPU core where driver installation happened */
386 
387 /**
388  * @brief Default configuration for Ethernet MAC object
389  *
390  */
391 #define ETH_MAC_DEFAULT_CONFIG()                          \
392     {                                                     \
393         .sw_reset_timeout_ms = 100,                       \
394         .rx_task_stack_size = 2048,                       \
395         .rx_task_prio = 15,                               \
396         .smi_mdc_gpio_num = 23,                           \
397         .smi_mdio_gpio_num = 18,                          \
398         .flags = 0,                                       \
399         .interface = EMAC_DATA_INTERFACE_RMII,            \
400         .clock_config =                                   \
401         {                                                 \
402             .rmii =                                       \
403             {                                             \
404                 .clock_mode = EMAC_CLK_DEFAULT,           \
405                 .clock_gpio = EMAC_CLK_IN_GPIO            \
406             }                                             \
407         }                                                 \
408     }
409 
410 #if CONFIG_ETH_USE_ESP32_EMAC
411 /**
412 * @brief Create ESP32 Ethernet MAC instance
413 *
414 * @param config: Ethernet MAC configuration
415 *
416 * @return
417 *      - instance: create MAC instance successfully
418 *      - NULL: create MAC instance failed because some error occurred
419 */
420 esp_eth_mac_t *esp_eth_mac_new_esp32(const eth_mac_config_t *config);
421 #endif // CONFIG_ETH_USE_ESP32_EMAC
422 
423 #if CONFIG_ETH_SPI_ETHERNET_DM9051
424 /**
425  * @brief DM9051 specific configuration
426  *
427  */
428 typedef struct {
429     void *spi_hdl;     /*!< Handle of SPI device driver */
430     int int_gpio_num;  /*!< Interrupt GPIO number */
431 } eth_dm9051_config_t;
432 
433 /**
434  * @brief Default DM9051 specific configuration
435  *
436  */
437 #define ETH_DM9051_DEFAULT_CONFIG(spi_device) \
438     {                                         \
439         .spi_hdl = spi_device,                \
440         .int_gpio_num = 4,                    \
441     }
442 
443 /**
444 * @brief Create DM9051 Ethernet MAC instance
445 *
446 * @param dm9051_config: DM9051 specific configuration
447 * @param mac_config: Ethernet MAC configuration
448 *
449 * @return
450 *      - instance: create MAC instance successfully
451 *      - NULL: create MAC instance failed because some error occurred
452 */
453 esp_eth_mac_t *esp_eth_mac_new_dm9051(const eth_dm9051_config_t *dm9051_config, const eth_mac_config_t *mac_config);
454 #endif // CONFIG_ETH_SPI_ETHERNET_DM9051
455 
456 #if CONFIG_ETH_SPI_ETHERNET_W5500
457 /**
458  * @brief W5500 specific configuration
459  *
460  */
461 typedef struct {
462     void *spi_hdl;     /*!< Handle of SPI device driver */
463     int int_gpio_num;  /*!< Interrupt GPIO number */
464 } eth_w5500_config_t;
465 
466 /**
467  * @brief Default W5500 specific configuration
468  *
469  */
470 #define ETH_W5500_DEFAULT_CONFIG(spi_device) \
471     {                                        \
472         .spi_hdl = spi_device,               \
473         .int_gpio_num = 4,                   \
474     }
475 
476 /**
477 * @brief Create W5500 Ethernet MAC instance
478 *
479 * @param w5500_config: W5500 specific configuration
480 * @param mac_config: Ethernet MAC configuration
481 *
482 * @return
483 *      - instance: create MAC instance successfully
484 *      - NULL: create MAC instance failed because some error occurred
485 */
486 esp_eth_mac_t *esp_eth_mac_new_w5500(const eth_w5500_config_t *w5500_config, const eth_mac_config_t *mac_config);
487 #endif // CONFIG_ETH_SPI_ETHERNET_W5500
488 
489 #if CONFIG_ETH_SPI_ETHERNET_KSZ8851SNL
490 /**
491  * @brief KSZ8851SNL specific configuration
492  *
493  */
494 typedef struct {
495     void *spi_hdl;     /*!< Handle of SPI device driver */
496     int int_gpio_num;  /*!< Interrupt GPIO number */
497 } eth_ksz8851snl_config_t;
498 
499 /**
500  * @brief Default KSZ8851SNL specific configuration
501  *
502  */
503 #define ETH_KSZ8851SNL_DEFAULT_CONFIG(spi_device) \
504     {                                        \
505         .spi_hdl = spi_device,               \
506         .int_gpio_num = 14,                   \
507     }
508 
509 /**
510 * @brief Create KSZ8851SNL Ethernet MAC instance
511 *
512 * @param ksz8851snl_config: KSZ8851SNL specific configuration
513 * @param mac_config: Ethernet MAC configuration
514 *
515 * @return
516 *      - instance: create MAC instance successfully
517 *      - NULL: create MAC instance failed because some error occurred
518 */
519 esp_eth_mac_t *esp_eth_mac_new_ksz8851snl(const eth_ksz8851snl_config_t *ksz8851snl_config, const eth_mac_config_t *mac_config);
520 #endif // CONFIG_ETH_SPI_ETHERNET_KSZ8851
521 
522 #if CONFIG_ETH_USE_OPENETH
523 /**
524 * @brief Create OpenCores Ethernet MAC instance
525 *
526 * @param config: Ethernet MAC configuration
527 *
528 * @return
529 *      - instance: create MAC instance successfully
530 *      - NULL: create MAC instance failed because some error occurred
531 */
532 esp_eth_mac_t *esp_eth_mac_new_openeth(const eth_mac_config_t *config);
533 #endif // CONFIG_ETH_USE_OPENETH
534 
535 #ifdef __cplusplus
536 }
537 #endif
538