]> granicus.if.org Git - esp-idf/commitdiff
ethernet: support flow control
authorshangke <shangke@espressif.com>
Fri, 6 Jan 2017 05:49:42 +0000 (13:49 +0800)
committershangke <shangke@espressif.com>
Tue, 10 Jan 2017 07:19:18 +0000 (15:19 +0800)
components/esp32/include/soc/dport_reg.h
components/esp32/phy_init.c
components/esp32/system_api.c
components/ethernet/emac_common.h
components/ethernet/emac_dev.c
components/ethernet/emac_dev.h
components/ethernet/emac_main.c
components/ethernet/include/esp_eth.h
docs/api/esp_eth.rst
examples/17_ethernet/main/ethernet_main.c
examples/17_ethernet/main/tlk110_phy.h

index f84346717c3809a1d400d79e8378313382fde551..ef231e316ed4f73f49b07443434ab207b3a035d9 100644 (file)
 #define DPORT_WIFI_CLK_EN_V  0xFFFFFFFF
 #define DPORT_WIFI_CLK_EN_S  0
 
-#define DPORT_WIFI_RST_EN_REG          (DR_REG_DPORT_BASE + 0x0D0)
-/* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
-/*description: */
+#define DPORT_CORE_RST_EN_REG          (DR_REG_DPORT_BASE + 0x0D0)
+/* DPORT_CORE_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */
+/*description: */
+#define DPROT_RW_BTLP_RST (BIT(10))
+#define DPROT_RW_BTMAC_RST (BIT(9))
+#define DPORT_MACPWR_RST (BIT(8))
+#define DPORT_EMAC_RST (BIT(7))
+#define DPORT_SDIO_HOST_RST (BIT(6))
+#define DPORT_SDIO_RST (BIT(5))
+#define DPORT_BTMAC_RST (BIT(4))
+#define DPORT_BT_RST (BIT(3))
 #define DPORT_MAC_RST (BIT(2))
-#define DPORT_WIFI_RST  0xFFFFFFFF
-#define DPORT_WIFI_RST_M  ((DPORT_WIFI_RST_V)<<(DPORT_WIFI_RST_S))
-#define DPORT_WIFI_RST_V  0xFFFFFFFF
-#define DPORT_WIFI_RST_S  0
+#define DPORT_FE_RST (BIT(1))
+#define DPORT_BB_RST (BIT(0))  
 
 #define DPORT_BT_LPCK_DIV_INT_REG          (DR_REG_DPORT_BASE + 0x0D4)
 /* DPORT_BTEXTWAKEUP_REQ : R/W ;bitpos:[12] ;default: 1'b0 ; */
index 6154beae908574b9544eb07926cdc59d77b89240..bfc5a15f5ed4268b67636b9b9dee22974ef933db 100644 (file)
@@ -39,8 +39,8 @@ esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data,
     assert(calibration_data);
     // Initialize PHY pointer table
     phy_get_romfunc_addr();
-    REG_SET_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST);
-    REG_CLR_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST);
+    REG_SET_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST);
+    REG_CLR_BIT(DPORT_CORE_RST_EN_REG, DPORT_MAC_RST);
     // Enable WiFi peripheral clock
     SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf);
     ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d",
index 63a28de5334b0f38e4cc1192d7df209471a6e322..60fa1796cdcabfe5135f4e1aa57c63cd2512629d 100644 (file)
@@ -111,9 +111,13 @@ void IRAM_ATTR esp_restart(void)
     uart_tx_wait_idle(1);
     uart_tx_wait_idle(2);
 
-    // Reset wifi/bluetooth (bb/mac)
-    SET_PERI_REG_MASK(DPORT_WIFI_RST_EN_REG, 0x1f);
-    REG_WRITE(DPORT_WIFI_RST_EN_REG, 0);
+    // Reset wifi/bluetooth/ethernet/sdio (bb/mac)
+    SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, 
+         DPORT_BB_RST | DPORT_FE_RST | DPORT_MAC_RST |
+         DPORT_BT_RST | DPORT_BTMAC_RST | DPORT_SDIO_RST |
+         DPORT_SDIO_HOST_RST | DPORT_EMAC_RST | DPORT_MACPWR_RST | 
+         DPROT_RW_BTMAC_RST | DPROT_RW_BTLP_RST);
+    REG_WRITE(DPORT_CORE_RST_EN_REG, 0);
 
     // Reset timer/spi/uart
     SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG,
index 774c287ad5a093bb540023fe386f4dd4a0dab983..957337d2a7808ed96e472cc22c99e2f4544a9e65 100644 (file)
@@ -72,6 +72,9 @@ struct emac_config_data {
     eth_phy_check_init_func emac_phy_check_init;
     eth_phy_get_speed_mode_func emac_phy_get_speed_mode;
     eth_phy_get_duplex_mode_func emac_phy_get_duplex_mode;
+    bool emac_flow_ctrl_enable;
+    bool emac_flow_ctrl_partner_support;
+    eth_phy_get_partner_pause_enable_func  emac_phy_get_partner_pause_enable;
 };
 
 enum emac_post_type {
@@ -109,6 +112,13 @@ struct emac_close_cmd {
 #define DMA_RX_BUF_SIZE 1600
 #define DMA_TX_BUF_SIZE 1600
 
+//rest buf num
+#define FLOW_CONTROL_HIGH_WATERMARK 3
+//used buf num
+#define FLOW_CONTROL_LOW_WATERMARK  6
+
+#define PHY_LINK_CHECK_NUM  5
+
 #define EMAC_CMD_OK 0
 #define EMAC_CMD_FAIL -1
 
index 244da084323f5846da65b7dc703b5e6109e37ff1..ba61bb750b6c6f0c985c58c496d858428a42c3af 100644 (file)
 
 static const char *TAG = "emac";
 
+void emac_enable_flowctrl(void)
+{
+    REG_SET_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_TRANSMIT_FLOW_CONTROL_ENABLE);
+    REG_SET_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_RECEIVE_FLOW_CONTROL_ENABLE);
+    REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_DISABLE_ZERO_QUANTA_PAUSE);
+    REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_TIME, 0x1648);
+    REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_LOW_THRESHOLD, 0x1);
+}
+
+void emac_disable_flowctrl(void)
+{
+    REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_TRANSMIT_FLOW_CONTROL_ENABLE);
+    REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_RECEIVE_FLOW_CONTROL_ENABLE);
+    REG_CLR_BIT(EMAC_GMACFLOWCONTROL_REG, EMAC_DISABLE_ZERO_QUANTA_PAUSE);
+    REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_TIME, 0);
+    REG_SET_FIELD(EMAC_GMACFLOWCONTROL_REG, EMAC_PAUSE_LOW_THRESHOLD, 0);
+}
+
 void emac_enable_dma_tx(void)
 {
     REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_START_STOP_TRANSMISSION_COMMAND);
@@ -100,18 +118,21 @@ void emac_dma_init(void)
     REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_FORWARD_UNDERSIZED_GOOD_FRAMES);
     REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_OPERATE_SECOND_FRAME);
     REG_SET_FIELD(EMAC_DMABUSMODE_REG, EMAC_PROG_BURST_LEN, 4);
-    REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG,EMAC_DMAOPERATION_MODE_REG);
+    REG_SET_BIT(EMAC_DMAOPERATION_MODE_REG, EMAC_DMAOPERATION_MODE_REG);
+}
+
+void emac_mac_enable_txrx(void)
+{
+    REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX);
+    REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX);
 }
 
 void emac_mac_init(void)
 {
     REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
     REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACMIIGMII);
-    REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
+    REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
     REG_SET_BIT(EMAC_GMACFRAMEFILTER_REG, EMAC_PROMISCUOUS_MODE);
-
-    REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACRX);
-    REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACTX);
 }
 
 void emac_set_clk_rmii(void)
index bc04d8d9e2ee9e4b314b77063e6b6d1840062eef..dc1045b92fe97b6d6609c4016397e6fa614e16bb 100644 (file)
@@ -52,6 +52,9 @@ void emac_enable_dma_tx(void);
 void emac_enable_dma_rx(void);
 void emac_disable_dma_tx(void);
 void emac_disable_dma_rx(void);
+void emac_enable_flowctrl(void);
+void emac_disable_flowctrl(void);
+void emac_mac_enable_txrx(void);
 
 uint32_t inline emac_read_tx_cur_reg(void)
 {
@@ -77,22 +80,32 @@ void inline emac_poll_rx_cmd(void)
 
 void inline emac_disable_rx_intr(void)
 {
-    REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE);
+    REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_INTERRUPT_ENABLE);
 }
 
 void inline emac_enable_rx_intr(void)
 {
-    REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_INTERRUPT_ENABLE);
+    REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_INTERRUPT_ENABLE);
 }
 
 void inline emac_disable_rx_unavail_intr(void)
 {
-    REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE);
+    REG_CLR_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE);
 }
 
 void inline emac_enable_rx_unavail_intr(void)
 {
-    REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG,EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE);  
+    REG_SET_BIT(EMAC_DMAINTERRUPT_EN_REG, EMAC_RECEIVE_BUFFER_UNAVAILABLE_ENABLE);
+}
+
+void IRAM_ATTR inline emac_send_pause_frame_enable(void)
+{
+    REG_SET_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL);
+}
+
+void inline emac_send_pause_zero_frame_enable(void)
+{
+    REG_CLR_BIT(EMAC_EX_PHYINF_CONF_REG, EMAC_EX_SBD_FLOWCTRL);
 }
 
 #ifdef __cplusplus
index 06e641453b18d7920cbeaca39278354c94cb1ca3..9446e8ee3547de2fc31036fae5beff2c542d9fdb 100644 (file)
@@ -68,6 +68,7 @@ static TimerHandle_t emac_timer = NULL;
 static SemaphoreHandle_t emac_rx_xMutex = NULL;
 static SemaphoreHandle_t emac_tx_xMutex = NULL;
 static const char *TAG = "emac";
+static bool pause_send = false;
 
 static esp_err_t emac_ioctl(emac_sig_t sig, emac_par_t par);
 esp_err_t emac_post(emac_sig_t sig, emac_par_t par);
@@ -96,9 +97,9 @@ static void emac_clean_tx_desc(struct dma_extended_desc *tx_desc)
     tx_desc->basic.desc0 = 0;
 }
 
-static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc ,uint32_t buf_ptr)
+static void emac_clean_rx_desc(struct dma_extended_desc *rx_desc , uint32_t buf_ptr)
 {
-    if(buf_ptr != 0) {
+    if (buf_ptr != 0) {
         rx_desc->basic.desc2 = buf_ptr;
     }
     rx_desc->basic.desc1 = EMAC_DESC_RX_SECOND_ADDR_CHAIN | DMA_RX_BUF_SIZE;
@@ -215,6 +216,8 @@ static void emac_set_user_config_data(eth_config_t *config )
     emac_config.emac_phy_check_init = config->phy_check_init;
     emac_config.emac_phy_get_speed_mode = config->phy_get_speed_mode;
     emac_config.emac_phy_get_duplex_mode = config->phy_get_duplex_mode;
+    emac_config.emac_flow_ctrl_enable = config->flow_ctrl_enable;
+    emac_config.emac_phy_get_partner_pause_enable = config->phy_get_partner_pause_enable;
 }
 
 static void emac_enable_intr()
@@ -276,6 +279,11 @@ static esp_err_t emac_verify_args(void)
         ret = ESP_FAIL;
     }
 
+    if (emac_config.emac_flow_ctrl_enable == true && emac_config.emac_phy_get_partner_pause_enable == NULL) {
+        ESP_LOGE(TAG, "phy get partner pause enable func is null");
+        ret = ESP_FAIL;
+    }
+
     return ret;
 }
 
@@ -293,13 +301,13 @@ static void emac_process_tx(void)
 {
     uint32_t cur_tx_desc = emac_read_tx_cur_reg();
 
-    if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
+    if (emac_config.emac_status == EMAC_RUNTIME_STOP) {
         return;
     }
 
     xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
 
-    while (((uint32_t) &(emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) {
+    while (((uint32_t) & (emac_config.dma_etx[emac_config.dirty_tx].basic.desc0) != cur_tx_desc)) {
         emac_clean_tx_desc(&(emac_config.dma_etx[emac_config.dirty_tx]));
         emac_config.dirty_tx = (emac_config.dirty_tx + 1) % DMA_TX_BUF_NUM;
         emac_config.cnt_tx --;
@@ -317,21 +325,43 @@ void esp_eth_free_rx_buf(void *buf)
 {
     xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
 
-    emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]),(uint32_t) buf);
+    emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.cur_rx]), (uint32_t) buf);
     emac_config.cur_rx = (emac_config.cur_rx + 1) % DMA_RX_BUF_NUM;
     emac_config.cnt_rx--;
-    if(emac_config.cnt_rx < 0) {
-       ESP_LOGE(TAG, "emac rx buf err!!\n");
+    if (emac_config.cnt_rx < 0) {
+        ESP_LOGE(TAG, "emac rx buf err!!\n");
     }
     emac_poll_rx_cmd();
 
     xSemaphoreGiveRecursive( emac_rx_xMutex );
+
+    if (emac_config.emac_flow_ctrl_partner_support == true) {
+        portENTER_CRITICAL(&g_emac_mux);
+        if (pause_send == true && emac_config.cnt_rx < FLOW_CONTROL_LOW_WATERMARK) {
+            emac_send_pause_zero_frame_enable();
+            pause_send = false;
+        }
+        portEXIT_CRITICAL(&g_emac_mux);
+    }
+}
+
+static uint32_t IRAM_ATTR emac_get_rxbuf_count_in_intr(void)
+{
+    uint32_t cnt = 0;
+    uint32_t cur_rx_desc = emac_read_rx_cur_reg();
+    struct dma_extended_desc *cur_desc = (struct dma_extended_desc *)cur_rx_desc;
+
+    while (cur_desc->basic.desc0 == EMAC_DESC_RX_OWN) {
+        cnt++;
+        cur_desc = (struct dma_extended_desc *)cur_desc->basic.desc3;
+    }
+    return cnt;
 }
 
 #if CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE
 static void emac_process_rx(void)
 {
-    if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
+    if (emac_config.emac_status == EMAC_RUNTIME_STOP) {
         return;
     }
     uint32_t cur_rx_desc = emac_read_rx_cur_reg();
@@ -341,7 +371,7 @@ static void emac_process_rx(void)
         emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
                                      (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
 
-        emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
+        emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
         emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
 
         //if open this ,one intr can do many intrs ?
@@ -353,14 +383,14 @@ static void emac_process_rx(void)
 
 static void emac_process_rx_unavail(void)
 {
-    if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
+    if (emac_config.emac_status == EMAC_RUNTIME_STOP) {
         return;
     }
 
     uint32_t dirty_cnt = 0;
     while (dirty_cnt < DMA_RX_BUF_NUM) {
 
-        if(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
+        if (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 == EMAC_DESC_RX_OWN) {
             break;
         }
 
@@ -369,7 +399,7 @@ static void emac_process_rx_unavail(void)
         emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
                                      (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
 
-        emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]),(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
+        emac_clean_rx_desc(&(emac_config.dma_erx[emac_config.dirty_rx]), (emac_config.dma_erx[emac_config.dirty_rx].basic.desc2));
         emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
     }
     emac_enable_rx_intr();
@@ -380,7 +410,7 @@ static void emac_process_rx_unavail(void)
 #else
 static void emac_process_rx_unavail(void)
 {
-    if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
+    if (emac_config.emac_status == EMAC_RUNTIME_STOP) {
         return;
     }
 
@@ -388,11 +418,11 @@ static void emac_process_rx_unavail(void)
 
     while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
 
-        //copy data to lwip 
+        //copy data to lwip
         emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
                                      (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
         emac_config.cnt_rx++;
-        if(emac_config.cnt_rx > DMA_RX_BUF_NUM) {
+        if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
             ESP_LOGE(TAG, "emac rx unavail buf err !!\n");
         }
         emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
@@ -404,7 +434,7 @@ static void emac_process_rx_unavail(void)
 
 static void emac_process_rx(void)
 {
-    if(emac_config.emac_status == EMAC_RUNTIME_STOP) {
+    if (emac_config.emac_status == EMAC_RUNTIME_STOP) {
         return;
     }
 
@@ -412,16 +442,16 @@ static void emac_process_rx(void)
 
     xSemaphoreTakeRecursive( emac_rx_xMutex, ( TickType_t ) portMAX_DELAY );
 
-    if(((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
+    if (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc)) {
 
-        while (((uint32_t) &(emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) {
+        while (((uint32_t) & (emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) != cur_rx_desc) && emac_config.cnt_rx < DMA_RX_BUF_NUM ) {
             //copy data to lwip
             emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
-                               (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
+                                         (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
 
             emac_config.cnt_rx++;
 
-            if(emac_config.cnt_rx > DMA_RX_BUF_NUM ) {
+            if (emac_config.cnt_rx > DMA_RX_BUF_NUM ) {
                 ESP_LOGE(TAG, "emac rx buf err!!\n");
             }
             emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
@@ -429,16 +459,16 @@ static void emac_process_rx(void)
             cur_rx_desc = emac_read_rx_cur_reg();
         }
     } else {
-        if(emac_config.cnt_rx < DMA_RX_BUF_NUM) {
-            if((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) {
+        if (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
+            if ((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0 & EMAC_DESC_RX_OWN) == 0) {
                 while (emac_config.cnt_rx < DMA_RX_BUF_NUM) {
 
                     //copy data to lwip
                     emac_config.emac_tcpip_input((void *)(emac_config.dma_erx[emac_config.dirty_rx].basic.desc2),
-                               (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
+                                                 (((emac_config.dma_erx[emac_config.dirty_rx].basic.desc0) >> EMAC_DESC_FRAME_LENGTH_S) & EMAC_DESC_FRAME_LENGTH) , NULL);
                     emac_config.cnt_rx++;
-                    if(emac_config.cnt_rx > DMA_RX_BUF_NUM) {
-                        ESP_LOGE(TAG,"emac rx buf err!!!\n");
+                    if (emac_config.cnt_rx > DMA_RX_BUF_NUM) {
+                        ESP_LOGE(TAG, "emac rx buf err!!!\n");
                     }
 
                     emac_config.dirty_rx = (emac_config.dirty_rx + 1) % DMA_RX_BUF_NUM;
@@ -462,12 +492,18 @@ static void IRAM_ATTR emac_process_intr(void *arg)
 
     if (event & EMAC_RECV_INT) {
         emac_disable_rx_intr();
+        if (emac_config.emac_flow_ctrl_partner_support == true) {
+            if (emac_get_rxbuf_count_in_intr() < FLOW_CONTROL_HIGH_WATERMARK && pause_send == false ) {
+                pause_send = true;
+                emac_send_pause_frame_enable();
+            }
+        }
         emac_post(SIG_EMAC_RX_DONE, 0);
     }
 
     if (event & EMAC_RECV_BUF_UNAVAIL) {
         emac_disable_rx_unavail_intr();
-        emac_post(SIG_EMAC_RX_UNAVAIL,0);
+        emac_post(SIG_EMAC_RX_UNAVAIL, 0);
     }
 
     if (event & EMAC_TRANS_INT) {
@@ -475,25 +511,43 @@ static void IRAM_ATTR emac_process_intr(void *arg)
     }
 }
 
+static void emac_set_macaddr_reg(void)
+{
+    REG_SET_FIELD(EMAC_GMACADDR0HIGH_REG, EMAC_MAC_ADDRESS0_HI, (emac_config.macaddr[0] << 8) | (emac_config.macaddr[1]));
+    REG_WRITE(EMAC_GMACADDR0LOW_REG, (emac_config.macaddr[2] << 24) |  (emac_config.macaddr[3] << 16) | (emac_config.macaddr[4] << 8) | (emac_config.macaddr[5]));
+}
+
 static void emac_check_phy_init(void)
 {
     emac_config.emac_phy_check_init();
-    if(emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) {
+    if (emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) {
         REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
     } else {
         REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACDUPLEX);
     }
-    if(emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) {
+    if (emac_config.emac_phy_get_speed_mode() == ETH_SPEED_MODE_100M) {
         REG_SET_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
     } else {
         REG_CLR_BIT(EMAC_GMACCONFIG_REG, EMAC_GMACFESPEED);
     }
-
-    emac_mac_init();
+    if (emac_config.emac_flow_ctrl_enable == true) {
+        if (emac_config.emac_phy_get_partner_pause_enable() == true && emac_config.emac_phy_get_duplex_mode() == ETH_MDOE_FULLDUPLEX) {
+            emac_enable_flowctrl();
+            emac_config.emac_flow_ctrl_partner_support = true;
+        } else {
+            emac_disable_flowctrl();
+            emac_config.emac_flow_ctrl_partner_support = false;
+        }
+    } else {
+        emac_disable_flowctrl();
+        emac_config.emac_flow_ctrl_partner_support = false;
+    }
+    emac_mac_enable_txrx();
 }
 static void emac_process_link_updown(bool link_status)
 {
     system_event_t evt;
+    uint8_t i = 0;
 
     emac_config.phy_link_up = link_status;
 
@@ -502,6 +556,10 @@ static void emac_process_link_updown(bool link_status)
         ESP_LOGI(TAG, "eth link_up!!!");
         emac_enable_dma_tx();
         emac_enable_dma_rx();
+        for (i = 0; i < PHY_LINK_CHECK_NUM; i++) {
+            emac_check_phy_init();
+        }
+
         evt.event_id = SYSTEM_EVENT_ETH_CONNECTED;
     } else {
         ESP_LOGI(TAG, "eth link_down!!!");
@@ -534,7 +592,7 @@ esp_err_t esp_eth_tx(uint8_t *buf, uint16_t size)
     }
 
     xSemaphoreTakeRecursive( emac_tx_xMutex, ( TickType_t ) portMAX_DELAY );
-    if (emac_config.cnt_tx == DMA_TX_BUF_NUM -1) {
+    if (emac_config.cnt_tx == DMA_TX_BUF_NUM - 1) {
         ESP_LOGD(TAG, "tx buf full");
         ret = ERR_MEM;
         goto _exit;
@@ -557,13 +615,13 @@ _exit:
 
 static void emac_init_default_data(void)
 {
-    memset((uint8_t *)&emac_config, 0,sizeof(struct emac_config_data));
+    memset((uint8_t *)&emac_config, 0, sizeof(struct emac_config_data));
 }
 
-void emac_process_link_check(void) 
+void emac_process_link_check(void)
 {
     if (emac_config.emac_status != EMAC_RUNTIME_START ||
-        emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
+            emac_config.emac_status == EMAC_RUNTIME_NOT_INIT) {
         return;
     }
 
@@ -580,7 +638,7 @@ void emac_process_link_check(void)
 
 void emac_link_check_func(void *pv_parameters)
 {
-    emac_post(SIG_EMAC_CHECK_LINK,0);
+    emac_post(SIG_EMAC_CHECK_LINK, 0);
 }
 
 static bool emac_link_check_timer_init(void)
@@ -634,10 +692,13 @@ static void emac_start(void *param)
     emac_check_mac_addr();
 
     emac_set_mac_addr();
+    emac_set_macaddr_reg();
 
     emac_set_tx_base_reg();
     emac_set_rx_base_reg();
 
+    emac_mac_init();
+
     emac_config.phy_init();
 
     //ptp TODO
@@ -818,7 +879,7 @@ void emac_task(void *pv)
 
 esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par)
 {
-    if(sig <= SIG_EMAC_RX_DONE) {
+    if (sig <= SIG_EMAC_RX_DONE) {
         if (emac_sig_cnt[sig]) {
             return ESP_OK;
         } else {
@@ -831,11 +892,11 @@ esp_err_t IRAM_ATTR emac_post(emac_sig_t sig, emac_par_t par)
 
             ret = xQueueSendFromISR(emac_xqueue, &evt, &tmp);
 
-            if(tmp != pdFALSE) {
+            if (tmp != pdFALSE) {
                 portYIELD_FROM_ISR();
             }
 
-            if(ret != pdPASS) {
+            if (ret != pdPASS) {
                 return ESP_FAIL;
             }
         }
index 2aae9d202497b62575baf0c71b954762625b0c77..e36c3ebfe6a68d9c70804002cc128ff09c058695 100644 (file)
@@ -79,6 +79,7 @@ typedef eth_duplex_mode_t (*eth_phy_get_duplex_mode_func)(void);
 typedef void (*eth_phy_func)(void);
 typedef esp_err_t (*eth_tcpip_input_func)(void *buffer, uint16_t len, void *eb);
 typedef void (*eth_gpio_config_func)(void);
+typedef bool (*eth_phy_get_partner_pause_enable_func)(void);
 
 
 /**
@@ -95,6 +96,9 @@ typedef struct {
     eth_phy_get_speed_mode_func phy_get_speed_mode;     /*!< phy check init func  */
     eth_phy_get_duplex_mode_func phy_get_duplex_mode;     /*!< phy check init func  */
     eth_gpio_config_func gpio_config;           /*!< gpio config func  */
+    bool flow_ctrl_enable;                      /*!< flag of flow ctrl enable */
+    eth_phy_get_partner_pause_enable_func  phy_get_partner_pause_enable; /*!< get partner pause enable */
+    
 } eth_config_t;
 
 /**
index 1fcb1c23513fb6af892d709e98f8ecf9ec03c6d0..371aa5b2333c3a7b4f194cd444cd0cb182997c61 100644 (file)
@@ -28,6 +28,7 @@ Type Definitions
 .. doxygentypedef:: eth_phy_func
 .. doxygentypedef:: eth_tcpip_input_func
 .. doxygentypedef:: eth_gpio_config_func
+.. doxygentypedef:: eth_phy_get_partner_pause_enable_func
 
 Enumerations
 ^^^^^^^^^^^^
index fc4347f7d893a57091d25d8a94e055d62487a06a..57c6f9735799550d558f62ef6b32fbf26b9d7c95 100644 (file)
@@ -71,6 +71,22 @@ bool phy_tlk110_check_phy_link_status(void)
     return ((esp_eth_smi_read(BASIC_MODE_STATUS_REG) & LINK_STATUS) == LINK_STATUS );
 }
 
+bool phy_tlk110_get_partner_pause_enable(void)
+{
+    if((esp_eth_smi_read(PHY_LINK_PARTNER_ABILITY_REG) & PARTNER_PAUSE) == PARTNER_PAUSE) {
+        return true;
+    } else {
+        return false;
+    }   
+}
+
+void phy_enable_flow_ctrl(void)
+{
+    uint32_t data = 0;
+    data = esp_eth_smi_read(AUTO_NEG_ADVERTISEMENT_REG);
+    esp_eth_smi_write(AUTO_NEG_ADVERTISEMENT_REG,data|ASM_DIR|PAUSE);
+}
+
 void phy_tlk110_init(void)
 {
     esp_eth_smi_write(PHY_RESET_CONTROL_REG, SOFTWARE_RESET);
@@ -78,8 +94,12 @@ void phy_tlk110_init(void)
     while (esp_eth_smi_read(PHY_IDENTIFIER_REG) != OUI_MSB_21TO6_DEF) {
     }
 
-    esp_eth_smi_write(SOFTWARE_STAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE);
+    esp_eth_smi_write(SOFTWARE_STRAP_CONTROL_REG, DEFAULT_PHY_CONFIG |SW_STRAP_CONFIG_DONE);
+    
     ets_delay_us(300);
+
+    //if config.flow_ctrl_enable == true ,enable this 
+    phy_enable_flow_ctrl();
 }
 
 void eth_gpio_config_rmii(void)
@@ -140,6 +160,9 @@ void app_main()
     config.phy_check_link = phy_tlk110_check_phy_link_status;
     config.phy_get_speed_mode = phy_tlk110_get_speed_mode;
     config.phy_get_duplex_mode = phy_tlk110_get_duplex_mode;
+    //Only FULLDUPLEX mode support flow ctrl now!
+    config.flow_ctrl_enable = true;
+    config.phy_get_partner_pause_enable = phy_tlk110_get_partner_pause_enable;    
 
     ret = esp_eth_init(&config);
 
index 5f2ca644dc8ded5efe760c059b285a5f282f924b..a21bc57aeab7a0a6aceb2b46d61036b01a4afd5e 100644 (file)
@@ -5,7 +5,15 @@
 #define PHY_IDENTIFIER_REG              (0x2)
 #define OUI_MSB_21TO6_DEF                      0x2000
 
-#define SOFTWARE_STAP_CONTROL_REG       (0x9)
+#define AUTO_NEG_ADVERTISEMENT_REG      (0x4)
+#define ASM_DIR                            BIT(11)
+#define PAUSE                              BIT(10)
+
+#define PHY_LINK_PARTNER_ABILITY_REG    (0x5)
+#define PARTNER_ASM_DIR                    BIT(11)
+#define PARTNER_PAUSE                      BIT(10) 
+
+#define SOFTWARE_STRAP_CONTROL_REG       (0x9)
 #define SW_STRAP_CONFIG_DONE               BIT(15)
 #define AUTO_MDIX_ENABLE                   BIT(14)
 #define AUTO_NEGOTIATION_ENABLE            BIT(13)