parent
b11cb41ae7
commit
58769e67c6
|
@ -8,6 +8,7 @@
|
||||||
* 2017-10-10 Tanek the first version
|
* 2017-10-10 Tanek the first version
|
||||||
* 2019-5-10 misonyo add DMA TX and RX function
|
* 2019-5-10 misonyo add DMA TX and RX function
|
||||||
* 2020-10-14 wangqiang use phy device in phy monitor thread
|
* 2020-10-14 wangqiang use phy device in phy monitor thread
|
||||||
|
* 2022-08-29 xjy198903 add 1170 rgmii support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
|
@ -29,8 +30,8 @@
|
||||||
#include <netif/ethernetif.h>
|
#include <netif/ethernetif.h>
|
||||||
#include "lwipopts.h"
|
#include "lwipopts.h"
|
||||||
|
|
||||||
#define ENET_RXBD_NUM (4)
|
#define ENET_RXBD_NUM (5)
|
||||||
#define ENET_TXBD_NUM (4)
|
#define ENET_TXBD_NUM (3)
|
||||||
#define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
|
#define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN)
|
||||||
#define ENET_TXBUFF_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)
|
void _enet_tx_callback(struct rt_imxrt_eth *eth)
|
||||||
{
|
{
|
||||||
|
dbg_log(DBG_LOG, "_enet_tx_callback\n");
|
||||||
if (eth->tx_is_waiting == RT_TRUE)
|
if (eth->tx_is_waiting == RT_TRUE)
|
||||||
{
|
{
|
||||||
eth->tx_is_waiting = RT_FALSE;
|
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;
|
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 */
|
/* ethernet device interface */
|
||||||
/* transmit packet. */
|
/* transmit packet. */
|
||||||
rt_err_t rt_imxrt_eth_tx(rt_device_t dev, struct pbuf *p)
|
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
|
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)
|
if (result == kStatus_ENET_TxFrameBusy)
|
||||||
{
|
{
|
||||||
|
@ -730,7 +1003,7 @@ static int rt_hw_imxrt_eth_init(void)
|
||||||
tid = rt_thread_create("phy",
|
tid = rt_thread_create("phy",
|
||||||
phy_monitor_thread_entry,
|
phy_monitor_thread_entry,
|
||||||
RT_NULL,
|
RT_NULL,
|
||||||
1024,
|
4096,
|
||||||
RT_THREAD_PRIORITY_MAX - 2,
|
RT_THREAD_PRIORITY_MAX - 2,
|
||||||
2);
|
2);
|
||||||
if (tid != RT_NULL)
|
if (tid != RT_NULL)
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2020-10-14 wangqiang the first version
|
* 2020-10-14 wangqiang the first version
|
||||||
|
* 2022-08-29 xjy198903 add rt1170 support
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <rtthread.h>
|
#include <rtthread.h>
|
||||||
|
@ -71,7 +72,12 @@
|
||||||
#define PHY_TIMEOUT_COUNT 0x3FFFFFFU
|
#define PHY_TIMEOUT_COUNT 0x3FFFFFFU
|
||||||
|
|
||||||
/* defined the Reset pin, PORT and PIN config by menuconfig */
|
/* 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)
|
#define RESET_PIN GET_PIN(PHY_RESET_PORT, PHY_RESET_PIN)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Prototypes
|
* Prototypes
|
||||||
|
|
Loading…
Reference in New Issue