Browse Source

修复imxrt1170网络驱动问题 (#6342)

1、修复ksz8081.c编译错误;
2、修复rt1170网络驱动问题
xjy198903 2 years ago
parent
commit
58769e67c6
2 changed files with 283 additions and 4 deletions
  1. 277 4
      bsp/imxrt/libraries/drivers/drv_eth.c
  2. 6 0
      bsp/imxrt/libraries/drivers/drv_ksz8081.c

+ 277 - 4
bsp/imxrt/libraries/drivers/drv_eth.c

@@ -8,6 +8,7 @@
  * 2017-10-10     Tanek        the first version
  * 2019-5-10      misonyo      add DMA TX and RX function
  * 2020-10-14     wangqiang    use phy device in phy monitor thread
+ * 2022-08-29     xjy198903    add 1170 rgmii support
  */
 
 #include <rtthread.h>
@@ -29,8 +30,8 @@
 #include <netif/ethernetif.h>
 #include "lwipopts.h"
 
-#define ENET_RXBD_NUM (4)
-#define ENET_TXBD_NUM (4)
+#define ENET_RXBD_NUM (5)
+#define ENET_TXBD_NUM (3)
 #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
 #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
 
@@ -122,6 +123,7 @@ void _enet_rx_callback(struct rt_imxrt_eth *eth)
 
 void _enet_tx_callback(struct rt_imxrt_eth *eth)
 {
+    dbg_log(DBG_LOG, "_enet_tx_callback\n");
     if (eth->tx_is_waiting == RT_TRUE)
     {
         eth->tx_is_waiting = RT_FALSE;
@@ -451,6 +453,277 @@ static rt_err_t rt_imxrt_eth_control(rt_device_t dev, int cmd, void *args)
     return RT_EOK;
 }
 
+static bool _ENET_TxDirtyRingAvailable(enet_tx_dirty_ring_t *txDirtyRing)
+{
+    return !txDirtyRing->isFull;
+}
+
+static uint16_t _ENET_IncreaseIndex(uint16_t index, uint16_t max)
+{
+    assert(index < max);
+
+    /* Increase the index. */
+    index++;
+    if (index >= max)
+    {
+        index = 0;
+    }
+    return index;
+}
+
+static void _ENET_ActiveSendRing(ENET_Type *base, uint8_t ringId)
+{
+    assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+    volatile uint32_t *txDesActive = NULL;
+
+    /* Ensure previous data update is completed with Data Synchronization Barrier before activing Tx BD. */
+    __DSB();
+
+    switch (ringId)
+    {
+    case 0:
+        txDesActive = &(base->TDAR);
+        break;
+#if FSL_FEATURE_ENET_QUEUE > 1
+    case 1:
+        txDesActive = &(base->TDAR1);
+        break;
+    case 2:
+        txDesActive = &(base->TDAR2);
+        break;
+#endif /* FSL_FEATURE_ENET_QUEUE > 1 */
+    default:
+        txDesActive = &(base->TDAR);
+        break;
+    }
+
+#if defined(FSL_FEATURE_ENET_HAS_ERRATA_007885) && FSL_FEATURE_ENET_HAS_ERRATA_007885
+    /* There is a TDAR race condition for mutliQ when the software sets TDAR
+     * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles).
+     * This will cause the udma_tx and udma_tx_arbiter state machines to hang.
+     * Software workaround: introduces a delay by reading the relevant ENET_TDARn_TDAR 4 times
+     */
+    for (uint8_t i = 0; i < 4U; i++)
+    {
+        if (*txDesActive == 0U)
+        {
+            break;
+        }
+    }
+#endif
+
+    /* Write to active tx descriptor */
+    *txDesActive = 0;
+}
+
+static status_t _ENET_SendFrame(ENET_Type *base,
+                                enet_handle_t *handle,
+                                const uint8_t *data,
+                                uint32_t length,
+                                uint8_t ringId,
+                                bool tsFlag,
+                                void *context)
+{
+    assert(handle != NULL);
+    assert(data != NULL);
+    assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1);
+    assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base));
+
+    volatile enet_tx_bd_struct_t *curBuffDescrip;
+    enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId];
+    enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId];
+    enet_frame_info_t *txDirty = NULL;
+    uint32_t len = 0;
+    uint32_t sizeleft = 0;
+    uint32_t address;
+    status_t result = kStatus_Success;
+    uint32_t src;
+    uint32_t configVal;
+    bool isReturn = false;
+    uint32_t primask;
+
+    /* Check the frame length. */
+    if (length > ENET_FRAME_TX_LEN_LIMITATION(base))
+    {
+        result = kStatus_ENET_TxFrameOverLen;
+    }
+    else
+    {
+        /* Check if the transmit buffer is ready. */
+        curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+        if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK))
+        {
+            result = kStatus_ENET_TxFrameBusy;
+        }
+        /* Check txDirtyRing if need frameinfo in tx interrupt callback. */
+        else if ((handle->txReclaimEnable[ringId]) && !_ENET_TxDirtyRingAvailable(txDirtyRing))
+        {
+            result = kStatus_ENET_TxFrameBusy;
+        }
+        else
+        {
+            /* One transmit buffer is enough for one frame. */
+            if (handle->txBuffSizeAlign[ringId] >= length)
+            {
+                /* Copy data to the buffer for uDMA transfer. */
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+                address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+                address = (uint32_t)curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+                pbuf_copy_partial((const struct pbuf *)data, (void *)address, length, 0);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+                if (handle->txMaintainEnable[ringId])
+                {
+                    DCACHE_CleanByRange(address, length);
+                }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+                /* Set data length. */
+                curBuffDescrip->length = (uint16_t)length;
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+                /* For enable the timestamp. */
+                if (tsFlag)
+                {
+                    curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+                }
+                else
+                {
+                    curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+                }
+
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+                curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
+
+                /* Increase the buffer descriptor address. */
+                txBdRing->txGenIdx = _ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+                /* Add context to frame info ring */
+                if (handle->txReclaimEnable[ringId])
+                {
+                    txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+                    txDirty->context = context;
+                    txDirtyRing->txGenIdx = _ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+                    if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+                    {
+                        txDirtyRing->isFull = true;
+                    }
+                    primask = DisableGlobalIRQ();
+                    txBdRing->txDescUsed++;
+                    EnableGlobalIRQ(primask);
+                }
+
+                /* Active the transmit buffer descriptor. */
+                _ENET_ActiveSendRing(base, ringId);
+            }
+            else
+            {
+                /* One frame requires more than one transmit buffers. */
+                do
+                {
+#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE
+                    /* For enable the timestamp. */
+                    if (tsFlag)
+                    {
+                        curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK;
+                    }
+                    else
+                    {
+                        curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK);
+                    }
+#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */
+
+                    /* Update the size left to be transmit. */
+                    sizeleft = length - len;
+#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
+                    address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local);
+#else
+                    address = (uint32_t)curBuffDescrip->buffer;
+#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
+                    src = (uint32_t)data + len;
+
+                    /* Increase the current software index of BD */
+                    txBdRing->txGenIdx = _ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
+
+                    if (sizeleft > handle->txBuffSizeAlign[ringId])
+                    {
+                        /* Data copy. */
+                        (void)memcpy((void *)(uint32_t *)address, (void *)(uint32_t *)src,
+                                     handle->txBuffSizeAlign[ringId]);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+                        if (handle->txMaintainEnable[ringId])
+                        {
+                            /* Add the cache clean maintain. */
+                            DCACHE_CleanByRange(address, handle->txBuffSizeAlign[ringId]);
+                        }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+                        /* Data length update. */
+                        curBuffDescrip->length = handle->txBuffSizeAlign[ringId];
+                        len += handle->txBuffSizeAlign[ringId];
+                        /* Sets the control flag. */
+                        configVal = (uint32_t)curBuffDescrip->control;
+                        configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+                        configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK;
+                        curBuffDescrip->control = (uint16_t)configVal;
+
+                        if (handle->txReclaimEnable[ringId])
+                        {
+                            primask = DisableGlobalIRQ();
+                            txBdRing->txDescUsed++;
+                            EnableGlobalIRQ(primask);
+                        }
+
+                        /* Active the transmit buffer descriptor*/
+                        _ENET_ActiveSendRing(base, ringId);
+                    }
+                    else
+                    {
+                        (void)memcpy((void *)(uint32_t *)address, (void *)(uint32_t *)src, sizeleft);
+#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL
+                        if (handle->txMaintainEnable[ringId])
+                        {
+                            /* Add the cache clean maintain. */
+                            DCACHE_CleanByRange(address, sizeleft);
+                        }
+#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */
+                        curBuffDescrip->length = (uint16_t)sizeleft;
+                        /* Set Last buffer wrap flag. */
+                        curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK;
+
+                        if (handle->txReclaimEnable[ringId])
+                        {
+                            /* Add context to frame info ring */
+                            txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx;
+                            txDirty->context = context;
+                            txDirtyRing->txGenIdx = _ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
+                            if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
+                            {
+                                txDirtyRing->isFull = true;
+                            }
+                            primask = DisableGlobalIRQ();
+                            txBdRing->txDescUsed++;
+                            EnableGlobalIRQ(primask);
+                        }
+
+                        /* Active the transmit buffer descriptor. */
+                        _ENET_ActiveSendRing(base, ringId);
+                        isReturn = true;
+                        break;
+                    }
+                    /* Update the buffer descriptor address. */
+                    curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx;
+                } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK));
+
+                if (isReturn == false)
+                {
+                    result = kStatus_ENET_TxFrameBusy;
+                }
+            }
+        }
+    }
+    return result;
+}
+
 /* ethernet device interface */
 /* transmit packet. */
 rt_err_t rt_imxrt_eth_tx(rt_device_t dev, struct pbuf *p)
@@ -469,7 +742,7 @@ rt_err_t rt_imxrt_eth_tx(rt_device_t dev, struct pbuf *p)
 
     do
     {
-        result = ENET_SendFrame(imxrt_eth_device.enet_base, enet_handle, (const uint8_t *)p, p->tot_len, RING_ID, false, NULL);
+        result = _ENET_SendFrame(imxrt_eth_device.enet_base, enet_handle, (const uint8_t *)p, p->tot_len, RING_ID, false, NULL);
 
         if (result == kStatus_ENET_TxFrameBusy)
         {
@@ -730,7 +1003,7 @@ static int rt_hw_imxrt_eth_init(void)
         tid = rt_thread_create("phy",
                                phy_monitor_thread_entry,
                                RT_NULL,
-                               1024,
+                               4096,
                                RT_THREAD_PRIORITY_MAX - 2,
                                2);
         if (tid != RT_NULL)

+ 6 - 0
bsp/imxrt/libraries/drivers/drv_ksz8081.c

@@ -6,6 +6,7 @@
  * Change Logs:
  * Date           Author       Notes
  * 2020-10-14     wangqiang    the first version
+ * 2022-08-29     xjy198903    add rt1170 support
  */
 
 #include <rtthread.h>
@@ -71,7 +72,12 @@
 #define PHY_TIMEOUT_COUNT 0x3FFFFFFU
 
 /* defined the Reset pin, PORT and PIN config by menuconfig */
+#ifdef SOC_IMXRT1170_SERIES
+#define RESET_PIN GET_PIN(PHY_RESET_KSZ8081_PORT, PHY_RESET_KSZ8081_PIN)
+#else
 #define RESET_PIN GET_PIN(PHY_RESET_PORT, PHY_RESET_PIN)
+#endif
+
 
 /*******************************************************************************
  * Prototypes