parent
b11cb41ae7
commit
58769e67c6
|
@ -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,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
|
||||
|
|
Loading…
Reference in New Issue