1 /*
2  * Copyright 2019-2024 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "fsl_enet_qos.h"
8 /*******************************************************************************
9  * Definitions
10  ******************************************************************************/
11 
12 /* Component ID definition, used by tools. */
13 #ifndef FSL_COMPONENT_ID
14 #define FSL_COMPONENT_ID "platform.drivers.enet_qos"
15 #endif
16 
17 /*! @brief Defines 10^9 nanosecond. */
18 #define ENET_QOS_NANOSECS_ONESECOND (1000000000U)
19 /*! @brief Defines 10^6 microsecond.*/
20 #define ENET_QOS_MICRSECS_ONESECOND (1000000U)
21 
22 /*! @brief Rx buffer LSB ignore bits. */
23 #define ENET_QOS_RXBUFF_IGNORELSB_BITS (3U)
24 /*! @brief ENET FIFO size unit. */
25 #define ENET_QOS_FIFOSIZE_UNIT (256U)
26 /*! @brief ENET half-dulpex default IPG. */
27 #define ENET_QOS_HALFDUPLEX_DEFAULTIPG (4U)
28 /*! @brief ENET miminum ring length. */
29 #define ENET_QOS_MIN_RINGLEN (4U)
30 /*! @brief ENET wakeup filter numbers. */
31 #define ENET_QOS_WAKEUPFILTER_NUM (8U)
32 /*! @brief Requried systime timer frequency. */
33 #define ENET_QOS_SYSTIME_REQUIRED_CLK_MHZ (50U)
34 /*! @brief Ethernet VLAN tag length. */
35 #define ENET_QOS_FRAME_VLAN_TAGLEN 4U
36 
37 /*! @brief AVB TYPE */
38 #define ENET_QOS_AVBTYPE             0x22F0U
39 #define ENET_QOS_HEAD_TYPE_OFFSET    (12)
40 #define ENET_QOS_HEAD_AVBTYPE_OFFSET (16)
41 
42 /*! @brief Defines the macro for converting constants from host byte order to network byte order. */
43 #define ENET_QOS_HTONS(n) __REV16(n)
44 #define ENET_QOS_HTONL(n) __REV(n)
45 #define ENET_QOS_NTOHS(n) __REV16(n)
46 #define ENET_QOS_NTOHL(n) __REV(n)
47 
48 #define ENET_QOS_DMA_CHX_RX_CTRL_RBSZ
49 /*******************************************************************************
50  * Prototypes
51  ******************************************************************************/
52 
53 /*! @brief Mask the cache management code if cache control is disabled. */
54 #if !defined(FSL_ETH_ENABLE_CACHE_CONTROL)
55 #define ENET_QOS_DcacheInvalidateByRange(address, sizeByte)
56 #else
57 #define ENET_QOS_DcacheInvalidateByRange(address, sizeByte) DCACHE_InvalidateByRange(address, sizeByte)
58 #endif
59 
60 /*!
61  * @brief Increase the index in the ring.
62  *
63  * @param index The current index.
64  * @param max The size.
65  * @return the increased index.
66  */
67 static uint16_t ENET_QOS_IncreaseIndex(uint16_t index, uint16_t max);
68 
69 /*!
70  * @brief Poll status flag.
71  *
72  * @param regAddr The register address to read out status
73  * @param mask The mask to operate the register value.
74  * @param readyStatus Indicate readyStatus for the field
75  * @retval kStatus_Success Poll readyStatus Success.
76  * @retval kStatus_ENET_QOS_Timeout Poll readyStatus timeout.
77  */
78 static status_t ENET_QOS_PollStatusFlag(volatile uint32_t *regAddr, uint32_t mask, uint32_t readyStatus);
79 
80 /*!
81  * @brief Set ENET DMA controller with the configuration.
82  *
83  * @param base ENET peripheral base address.
84  * @param config ENET Mac configuration.
85  * @retval kStatus_Success         ENET DMA controller has been configured successfully.
86  * @retval kStatus_InvalidArgument Could not set the provided configuration.
87  */
88 static status_t ENET_QOS_SetDMAControl(ENET_QOS_Type *base, const enet_qos_config_t *config);
89 
90 /*!
91  * @brief Set ENET MAC controller with the configuration.
92  *
93  * @param base ENET peripheral base address.
94  * @param config ENET Mac configuration.
95  * @param macAddr ENET six-byte mac address.
96  * @retval kStatus_Success         ENET MAC controller has been configured successfully.
97  * @retval kStatus_InvalidArgument Could not set the provided configuration.
98  */
99 static status_t ENET_QOS_SetMacControl(ENET_QOS_Type *base,
100                                        const enet_qos_config_t *config,
101                                        uint8_t *macAddr,
102                                        uint8_t macCount);
103 /*!
104  * @brief Set ENET MTL with the configuration.
105  *
106  * @param base ENET peripheral base address.
107  * @param config ENET Mac configuration.
108  */
109 static void ENET_QOS_SetMTL(ENET_QOS_Type *base, const enet_qos_config_t *config);
110 
111 /*!
112  * @brief Set ENET DMA transmit buffer descriptors for one channel.
113  *
114  * @param base ENET peripheral base address.
115  * @param bufferConfig ENET buffer configuration.
116  * @param intTxEnable tx interrupt enable.
117  * @param channel The channel number, 0 , 1.
118  */
119 static status_t ENET_QOS_TxDescriptorsInit(ENET_QOS_Type *base,
120                                            const enet_qos_buffer_config_t *bufferConfig,
121                                            bool intTxEnable,
122                                            uint8_t channel);
123 
124 /*!
125  * @brief Set ENET DMA receive buffer descriptors for one channel.
126  *
127  * @param base ENET peripheral base address.
128  * @param bufferConfig ENET buffer configuration.
129  * @param intRxEnable tx interrupt enable.
130  * @param channel The channel number, 0, 1.
131  */
132 static status_t ENET_QOS_RxDescriptorsInit(ENET_QOS_Type *base,
133                                            enet_qos_config_t *config,
134                                            const enet_qos_buffer_config_t *bufferConfig,
135                                            bool intRxEnable,
136                                            uint8_t channel);
137 
138 /*!
139  * @brief Sets the ENET 1588 feature.
140  *
141  * Enable the enhacement 1588 buffer descriptor mode and start
142  * the 1588 timer.
143  *
144  * @param base ENET peripheral base address.
145  * @param config The ENET configuration.
146  * @param refClk_Hz The reference clock for ptp 1588.
147  */
148 static status_t ENET_QOS_SetPtp1588(ENET_QOS_Type *base, const enet_qos_config_t *config, uint32_t refClk_Hz);
149 
150 /*!
151  * @brief Store the receive time-stamp for event PTP frame in the time-stamp buffer ring.
152  *
153  * @param base   ENET peripheral base address.
154  * @param handle ENET handler.
155  * @param rxDesc The ENET receive descriptor pointer.
156  * @param channel The rx channel.
157  * @param ts The timestamp structure pointer.
158  */
159 static void ENET_QOS_StoreRxFrameTime(ENET_QOS_Type *base,
160                                       enet_qos_handle_t *handle,
161                                       enet_qos_rx_bd_struct_t *rxDesc,
162                                       //                                          uint8_t channel,
163                                       enet_qos_ptp_time_t *ts);
164 
165 /*!
166  * @brief Check if txDirtyRing available.
167  *
168  * @param txDirtyRing pointer to txDirtyRing
169  * @retval txDirty available status.
170  */
171 static inline bool ENET_QOS_TxDirtyRingAvailable(enet_qos_tx_dirty_ring_t *txDirtyRing);
172 
173 /*!
174  * @brief Check if the given MII configuration is valid and allowed.
175  *
176  * @param mode MII mode
177  * @param speed MII speed
178  * @retval true if configuration is valid, false otherwise
179  */
180 static inline bool ENET_QOS_IsMIIConfigValid(enet_qos_mii_mode_t mode, enet_qos_mii_speed_t speed);
181 
182 /*******************************************************************************
183  * Variables
184  ******************************************************************************/
185 /*! @brief Pointers to enet bases for each instance. */
186 static ENET_QOS_Type *const s_enetqosBases[] = ENET_QOS_BASE_PTRS;
187 
188 /*! @brief Pointers to enet IRQ number for each instance. */
189 static const IRQn_Type s_enetqosIrqId[] = ENET_QOS_IRQS;
190 
191 /* ENET ISR for transactional APIs. */
192 static enet_qos_isr_t s_enetqosIsr;
193 
194 /*! @brief Pointers to enet handles for each instance. */
195 static enet_qos_handle_t *s_ENETHandle[ARRAY_SIZE(s_enetqosBases)] = {NULL};
196 
197 /*! @brief Arrays of enet state structures for each instance. */
198 static enet_qos_state_t s_enetStates[ARRAY_SIZE(s_enetqosBases)] = {{}};
199 
200 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
201 /*! @brief Pointers to enet clocks for each instance. */
202 const clock_ip_name_t s_enetqosClock[ARRAY_SIZE(s_enetqosBases)] = ENETQOS_CLOCKS;
203 #endif /*  FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
204 
205 /*******************************************************************************
206  * Code
207  ******************************************************************************/
208 
ENET_QOS_PollStatusFlag(volatile uint32_t * regAddr,uint32_t mask,uint32_t readyStatus)209 static status_t ENET_QOS_PollStatusFlag(volatile uint32_t *regAddr, uint32_t mask, uint32_t readyStatus)
210 {
211     uint8_t retryTimes = 10U;
212     status_t result    = kStatus_Success;
213 
214     while ((readyStatus != (*regAddr & mask)) && (0U != retryTimes))
215     {
216         retryTimes--;
217         SDK_DelayAtLeastUs(1U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
218     }
219 
220     if (retryTimes == 0U)
221     {
222         result = kStatus_ENET_QOS_Timeout;
223     }
224 
225     return result;
226 }
227 
228 /*!
229  * brief Sets the ENET AVB feature.
230  *
231  * ENET_QOS AVB feature configuration, set transmit bandwidth.
232  * This API is called when the AVB feature is required.
233  *
234  * param base ENET_QOS peripheral base address.
235  * param config The ENET_QOS AVB feature configuration structure.
236  * param queueIndex ENET_QOS queue index.
237  */
ENET_QOS_AVBConfigure(ENET_QOS_Type * base,const enet_qos_cbs_config_t * config,uint8_t queueIndex)238 void ENET_QOS_AVBConfigure(ENET_QOS_Type *base, const enet_qos_cbs_config_t *config, uint8_t queueIndex)
239 {
240     assert(config != NULL);
241 
242     /* Enable AV algorithm */
243     base->MTL_QUEUE[queueIndex].MTL_TXQX_ETS_CTRL |= ENET_QOS_MTL_TXQX_ETS_CTRL_AVALG_MASK;
244     /* Configure send slope */
245     base->MTL_QUEUE[queueIndex].MTL_TXQX_SNDSLP_CRDT = config->sendSlope;
246     /* Configure idle slope (same register as tx weight) */
247     base->MTL_QUEUE[queueIndex].MTL_TXQX_QNTM_WGHT = config->idleSlope;
248     /* Configure high credit */
249     base->MTL_QUEUE[queueIndex].MTL_TXQX_HI_CRDT = config->highCredit;
250     /* Configure high credit */
251     base->MTL_QUEUE[queueIndex].MTL_TXQX_LO_CRDT = config->lowCredit;
252 }
253 
ENET_QOS_IncreaseIndex(uint16_t index,uint16_t max)254 static uint16_t ENET_QOS_IncreaseIndex(uint16_t index, uint16_t max)
255 {
256     /* Increase the index. */
257     index++;
258     if (index >= max)
259     {
260         index = 0;
261     }
262     return index;
263 }
264 
ENET_QOS_ReverseBits(uint32_t value)265 static uint32_t ENET_QOS_ReverseBits(uint32_t value)
266 {
267     value = ((value & 0x55555555UL) << 1U) | ((value >> 1U) & 0x55555555UL);
268     value = ((value & 0x33333333UL) << 2U) | ((value >> 2U) & 0x33333333UL);
269     value = ((value & 0x0F0F0F0FUL) << 4U) | ((value >> 4U) & 0x0F0F0F0FUL);
270 
271     return (value >> 24U) | ((value >> 8U) & 0xFF00UL) | ((value & 0xFF00UL) << 8U) | (value << 24U);
272 }
273 
ENET_QOS_SetDMAControl(ENET_QOS_Type * base,const enet_qos_config_t * config)274 static status_t ENET_QOS_SetDMAControl(ENET_QOS_Type *base, const enet_qos_config_t *config)
275 {
276     assert(config != NULL);
277 
278     uint8_t index;
279     uint32_t reg;
280     uint32_t burstLen;
281 
282     if (!ENET_QOS_IsMIIConfigValid(config->miiMode, config->miiSpeed))
283     {
284         return kStatus_InvalidArgument;
285     }
286 
287     if (kENET_QOS_RmiiMode == config->miiMode)
288     {
289         /* Disable enet qos clock first. */
290         ENET_QOS_EnableClock(false);
291     }
292     else
293     {
294         /* Enable enet qos clock. */
295         ENET_QOS_EnableClock(true);
296     }
297 
298     /* Set MII mode*/
299     ENET_QOS_SetSYSControl(config->miiMode);
300     s_enetStates[ENET_QOS_GetInstance(base)].miiMode = config->miiMode;
301 
302     /* Reset first, The reset bit will automatically be cleared after complete. */
303     base->DMA_MODE |= ENET_QOS_DMA_MODE_SWR_MASK;
304     for (uint32_t i = 0U; i < 100UL; i++)
305     {
306         __NOP();
307     }
308     if (kENET_QOS_RmiiMode == config->miiMode)
309     {
310         /* Configure mac */
311         reg = ENET_QOS_MAC_CONFIGURATION_DM(config->miiDuplex) | (uint32_t)config->miiSpeed |
312               ENET_QOS_MAC_CONFIGURATION_S2KP(
313                   ((config->specialControl & (uint32_t)kENET_QOS_8023AS2KPacket) != 0U) ? 1U : 0U);
314         if (config->miiDuplex == kENET_QOS_MiiHalfDuplex)
315         {
316             reg |= ENET_QOS_MAC_CONFIGURATION_IPG(ENET_QOS_HALFDUPLEX_DEFAULTIPG);
317         }
318         base->MAC_CONFIGURATION = reg;
319         /* Enable enet qos clock. */
320         ENET_QOS_EnableClock(true);
321         for (uint32_t i = 0U; i < 100UL; i++)
322         {
323             __NOP();
324         }
325     }
326     /* Wait for the complete */
327     while ((base->DMA_MODE & ENET_QOS_DMA_MODE_SWR_MASK) != 0U)
328     {
329     }
330 
331     /* Set the burst length. */
332     for (index = 0; index < ENET_QOS_RING_NUM_MAX; index++)
333     {
334         burstLen = (uint32_t)kENET_QOS_BurstLen1;
335         if (config->multiqueueCfg != NULL)
336         {
337             burstLen = (uint32_t)config->multiqueueCfg->burstLen;
338         }
339         base->DMA_CH[index].DMA_CHX_CTRL = burstLen & ENET_QOS_DMA_CHX_CTRL_PBLx8_MASK;
340 
341         reg = base->DMA_CH[index].DMA_CHX_TX_CTRL & ~ENET_QOS_DMA_CHX_TX_CTRL_TxPBL_MASK;
342         base->DMA_CH[index].DMA_CHX_TX_CTRL = reg | ENET_QOS_DMA_CHX_TX_CTRL_TxPBL(burstLen & 0x3FU);
343 
344         reg = base->DMA_CH[index].DMA_CHX_RX_CTRL & ~ENET_QOS_DMA_CHX_RX_CTRL_RxPBL_MASK;
345         base->DMA_CH[index].DMA_CHX_RX_CTRL = reg | ENET_QOS_DMA_CHX_RX_CTRL_RxPBL(burstLen & 0x3FU);
346     }
347 
348     return kStatus_Success;
349 }
350 
ENET_QOS_SetMTL(ENET_QOS_Type * base,const enet_qos_config_t * config)351 static void ENET_QOS_SetMTL(ENET_QOS_Type *base, const enet_qos_config_t *config)
352 {
353     assert(config != NULL);
354 
355     uint32_t txqOpreg                       = 0;
356     uint32_t rxqOpReg                       = 0;
357     enet_qos_multiqueue_config_t *multiqCfg = config->multiqueueCfg;
358     uint8_t index;
359 
360     /* Set transmit operation mode. */
361     if ((config->specialControl & (uint32_t)kENET_QOS_StoreAndForward) != 0U)
362     {
363         txqOpreg = ENET_QOS_MTL_TXQX_OP_MODE_TSF_MASK;
364         rxqOpReg = ENET_QOS_MTL_RXQX_OP_MODE_RSF_MASK;
365     }
366     /* Set transmit operation mode. */
367     txqOpreg |= ENET_QOS_MTL_TXQX_OP_MODE_FTQ_MASK;
368     /* Set receive operation mode. */
369     rxqOpReg |= ENET_QOS_MTL_RXQX_OP_MODE_FUP_MASK | ENET_QOS_MTL_RXQX_OP_MODE_RFD(3U) |
370                 ENET_QOS_MTL_RXQX_OP_MODE_RFA(1U) | ENET_QOS_MTL_RXQX_OP_MODE_EHFC_MASK;
371 
372     if (multiqCfg == NULL)
373     {
374         txqOpreg |=
375             ENET_QOS_MTL_TXQX_OP_MODE_TQS(((uint32_t)ENET_QOS_MTL_TXFIFOSIZE / (uint32_t)ENET_QOS_FIFOSIZE_UNIT - 1U));
376         rxqOpReg |=
377             ENET_QOS_MTL_RXQX_OP_MODE_RQS(((uint32_t)ENET_QOS_MTL_RXFIFOSIZE / (uint32_t)ENET_QOS_FIFOSIZE_UNIT - 1U));
378         base->MTL_QUEUE[0].MTL_TXQX_OP_MODE = txqOpreg | ENET_QOS_MTL_TXQX_OP_MODE_TXQEN((uint32_t)kENET_QOS_DCB_Mode);
379         base->MTL_QUEUE[0].MTL_RXQX_OP_MODE = rxqOpReg;
380     }
381     else
382     {
383         /* Set the schedule/arbitration(set for multiple queues). */
384         base->MTL_OPERATION_MODE = ENET_QOS_MTL_OPERATION_MODE_SCHALG(multiqCfg->mtltxSche) |
385                                    ENET_QOS_MTL_OPERATION_MODE_RAA(multiqCfg->mtlrxSche);
386 
387         for (index = 0; index < multiqCfg->txQueueUse; index++)
388         {
389             txqOpreg |= ENET_QOS_MTL_TXQX_OP_MODE_TQS(
390                 ((uint32_t)ENET_QOS_MTL_TXFIFOSIZE / ((uint32_t)multiqCfg->txQueueUse * ENET_QOS_FIFOSIZE_UNIT)) - 1U);
391             base->MTL_QUEUE[index].MTL_TXQX_OP_MODE =
392                 txqOpreg | ENET_QOS_MTL_TXQX_OP_MODE_TXQEN((uint32_t)multiqCfg->txQueueConfig[index].mode);
393             if (multiqCfg->txQueueConfig[index].mode == kENET_QOS_AVB_Mode)
394             {
395                 ENET_QOS_AVBConfigure(base, multiqCfg->txQueueConfig[index].cbsConfig, index);
396             }
397             else
398             {
399                 base->MTL_QUEUE[index].MTL_TXQX_QNTM_WGHT = multiqCfg->txQueueConfig[index].weight;
400             }
401         }
402 
403         volatile uint32_t *mtlrxQuemapReg;
404         uint8_t configIndex;
405         for (index = 0; index < multiqCfg->rxQueueUse; index++)
406         {
407             rxqOpReg |= ENET_QOS_MTL_RXQX_OP_MODE_RQS(
408                 ((uint32_t)ENET_QOS_MTL_RXFIFOSIZE / ((uint32_t)multiqCfg->rxQueueUse * ENET_QOS_FIFOSIZE_UNIT)) - 1U);
409             base->MTL_QUEUE[index].MTL_RXQX_OP_MODE = rxqOpReg;
410             mtlrxQuemapReg                          = (index < 4U) ? &base->MTL_RXQ_DMA_MAP0 : &base->MTL_RXQ_DMA_MAP1;
411             configIndex                             = (index & 0x3U);
412             *mtlrxQuemapReg &= ~((uint32_t)ENET_QOS_MTL_RXQ_DMA_MAP0_Q0MDMACH_MASK << (8U * configIndex));
413             *mtlrxQuemapReg |= (uint32_t)ENET_QOS_MTL_RXQ_DMA_MAP0_Q0MDMACH(multiqCfg->rxQueueConfig[index].mapChannel)
414                                << (8U * configIndex);
415         }
416     }
417 }
418 
ENET_QOS_SetMacControl(ENET_QOS_Type * base,const enet_qos_config_t * config,uint8_t * macAddr,uint8_t macCount)419 static status_t ENET_QOS_SetMacControl(ENET_QOS_Type *base,
420                                        const enet_qos_config_t *config,
421                                        uint8_t *macAddr,
422                                        uint8_t macCount)
423 {
424     assert(config != NULL);
425 
426     uint32_t reg = 0;
427 
428     if (!ENET_QOS_IsMIIConfigValid(config->miiMode, config->miiSpeed))
429     {
430         return kStatus_InvalidArgument;
431     }
432 
433     /* Set Macaddr */
434     /* The dma channel 0 is set as to which the rx packet
435      * whose DA matches the MAC address content is routed. */
436     if (macAddr != NULL)
437     {
438         for (uint8_t i = 0; i < macCount; i++)
439         {
440             ENET_QOS_SetMacAddr(base, macAddr, i);
441         }
442     }
443 
444     /* Set the receive filter. */
445     reg =
446         ENET_QOS_MAC_PACKET_FILTER_PR(((config->specialControl & (uint32_t)kENET_QOS_PromiscuousEnable) != 0U) ? 1U :
447                                                                                                                  0U) |
448         ENET_QOS_MAC_PACKET_FILTER_DBF(((config->specialControl & (uint32_t)kENET_QOS_BroadCastRxDisable) != 0U) ? 1U :
449                                                                                                                    0U) |
450         ENET_QOS_MAC_PACKET_FILTER_PM(((config->specialControl & (uint32_t)kENET_QOS_MulticastAllEnable) != 0U) ? 1U :
451                                                                                                                   0U) |
452         ENET_QOS_MAC_PACKET_FILTER_HMC(((config->specialControl & (uint32_t)kENET_QOS_HashMulticastEnable) != 0U) ? 1U :
453                                                                                                                     0U);
454     base->MAC_PACKET_FILTER = reg;
455     /* Flow control. */
456     if ((config->specialControl & (uint32_t)kENET_QOS_FlowControlEnable) != 0U)
457     {
458         base->MAC_RX_FLOW_CTRL      = ENET_QOS_MAC_RX_FLOW_CTRL_RFE_MASK | ENET_QOS_MAC_RX_FLOW_CTRL_UP_MASK;
459         base->MAC_TX_FLOW_CTRL_Q[0] = ENET_QOS_MAC_TX_FLOW_CTRL_Q_PT(config->pauseDuration);
460     }
461 
462     /* Set the 1us ticket. */
463     reg                         = config->csrClock_Hz / ENET_QOS_MICRSECS_ONESECOND - 1U;
464     base->MAC_ONEUS_TIC_COUNTER = ENET_QOS_MAC_ONEUS_TIC_COUNTER_TIC_1US_CNTR(reg);
465 
466     /* Set the speed and duplex. */
467     reg = ENET_QOS_MAC_CONFIGURATION_DM(config->miiDuplex) | (uint32_t)config->miiSpeed |
468           ENET_QOS_MAC_CONFIGURATION_S2KP(((config->specialControl & (uint32_t)kENET_QOS_8023AS2KPacket) != 0U) ? 1U :
469                                                                                                                   0U) |
470           ENET_QOS_MAC_CONFIGURATION_IPC(
471               ((config->specialControl & (uint32_t)kENET_QOS_RxChecksumOffloadEnable) != 0U) ? 1U : 0U);
472     if (config->miiDuplex == kENET_QOS_MiiHalfDuplex)
473     {
474         reg |= ENET_QOS_MAC_CONFIGURATION_IPG(ENET_QOS_HALFDUPLEX_DEFAULTIPG);
475     }
476     base->MAC_CONFIGURATION = reg;
477 
478     if (config->multiqueueCfg != NULL)
479     {
480         reg = 0U;
481         uint8_t configIndex;
482         enet_qos_multiqueue_config_t *multiqCfg = config->multiqueueCfg;
483         uint32_t txQueuePrioMap0                = base->MAC_TXQ_PRTY_MAP0;
484         uint32_t txQueuePrioMap1                = base->MAC_TXQ_PRTY_MAP1;
485         uint32_t rxQueuePrioMap0                = base->MAC_RXQ_CTRL[2];
486         uint32_t rxQueuePrioMap1                = base->MAC_RXQ_CTRL[3];
487         uint32_t rxCtrlReg1                     = base->MAC_RXQ_CTRL[1];
488 
489         for (uint8_t index = 0U; index < multiqCfg->txQueueUse; index++)
490         {
491             configIndex = index & 0x3U;
492 
493             /* Configure tx queue priority. */
494             if (index < 4U)
495             {
496                 txQueuePrioMap0 &= ~((uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK << (8U * configIndex));
497                 txQueuePrioMap0 |= (uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0(multiqCfg->txQueueConfig[index].priority)
498                                    << (8U * configIndex);
499             }
500             else
501             {
502                 txQueuePrioMap1 &= ~((uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK << (8U * configIndex));
503                 txQueuePrioMap1 |= (uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0(multiqCfg->txQueueConfig[index].priority)
504                                    << (8U * configIndex);
505             }
506         }
507 
508         for (uint8_t index = 0U; index < multiqCfg->rxQueueUse; index++)
509         {
510             configIndex = index & 0x3U;
511 
512             /* Configure rx queue priority. */
513             if (index < 4U)
514             {
515                 rxQueuePrioMap0 &= ~((uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0_MASK << (8U * configIndex));
516                 rxQueuePrioMap0 |= (uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0(multiqCfg->rxQueueConfig[index].priority)
517                                    << (8U * configIndex);
518             }
519             else
520             {
521                 rxQueuePrioMap1 &= ~((uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0_MASK << (8U * configIndex));
522                 rxQueuePrioMap1 |= (uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0(multiqCfg->rxQueueConfig[index].priority)
523                                    << (8U * configIndex);
524             }
525 
526             /* Configure queue enable mode. */
527             reg |= ENET_QOS_MAC_RXQ_CTRL_RXQ0EN((uint32_t)multiqCfg->rxQueueConfig[index].mode) << (2U * index);
528 
529             /* Configure rx queue routing */
530             if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketAVCPQ) != 0U)
531             {
532                 rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_AVCPQ_MASK;
533                 rxCtrlReg1 |= (ENET_QOS_MAC_RXQ_CTRL_AVCPQ(index) | ENET_QOS_MAC_RXQ_CTRL_TACPQE_MASK);
534             }
535 
536             if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketPTPQ) != 0U)
537             {
538                 rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_PTPQ_MASK;
539                 rxCtrlReg1 |= ENET_QOS_MAC_RXQ_CTRL_PTPQ(index);
540             }
541 
542             if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketDCBCPQ) != 0U)
543             {
544                 rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_DCBCPQ_MASK;
545                 rxCtrlReg1 |= ENET_QOS_MAC_RXQ_CTRL_DCBCPQ(index);
546             }
547 
548             if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketUPQ) != 0U)
549             {
550                 rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_UPQ_MASK;
551                 rxCtrlReg1 |= ENET_QOS_MAC_RXQ_CTRL_UPQ(index);
552             }
553 
554             if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketMCBCQ) != 0U)
555             {
556                 rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_MCBCQ_MASK;
557                 rxCtrlReg1 |= (ENET_QOS_MAC_RXQ_CTRL_MCBCQ(index) | ENET_QOS_MAC_RXQ_CTRL_MCBCQEN_MASK);
558             }
559         }
560 
561         base->MAC_TXQ_PRTY_MAP0 = txQueuePrioMap0;
562         base->MAC_TXQ_PRTY_MAP1 = txQueuePrioMap1;
563         base->MAC_RXQ_CTRL[2]   = rxQueuePrioMap0;
564         base->MAC_RXQ_CTRL[3]   = rxQueuePrioMap1;
565         base->MAC_RXQ_CTRL[1]   = rxCtrlReg1;
566     }
567     else
568     {
569         /* Configure queue enable mode. */
570         reg = ENET_QOS_MAC_RXQ_CTRL_RXQ0EN((uint32_t)kENET_QOS_DCB_Mode);
571     }
572 
573     /* Enable queue. */
574     base->MAC_RXQ_CTRL[0] = reg;
575 
576     /* Mask MMC counters interrupts as we don't handle
577      * them in the interrupt handler.
578      */
579     base->MAC_MMC_RX_INTERRUPT_MASK     = 0xFFFFFFFFU;
580     base->MAC_MMC_TX_INTERRUPT_MASK     = 0xFFFFFFFFU;
581     base->MAC_MMC_IPC_RX_INTERRUPT_MASK = 0xFFFFFFFFU;
582     base->MAC_MMC_FPE_RX_INTERRUPT_MASK = 0xFFFFFFFFU;
583     base->MAC_MMC_FPE_TX_INTERRUPT_MASK = 0xFFFFFFFFU;
584 
585     return kStatus_Success;
586 }
587 
ENET_QOS_TxDescriptorsInit(ENET_QOS_Type * base,const enet_qos_buffer_config_t * bufferConfig,bool intTxEnable,uint8_t channel)588 static status_t ENET_QOS_TxDescriptorsInit(ENET_QOS_Type *base,
589                                            const enet_qos_buffer_config_t *bufferConfig,
590                                            bool intTxEnable,
591                                            uint8_t channel)
592 {
593     uint16_t j;
594     enet_qos_tx_bd_struct_t *txbdPtr;
595     uint32_t control                        = intTxEnable ? ENET_QOS_TXDESCRIP_RD_IOC_MASK : 0U;
596     const enet_qos_buffer_config_t *buffCfg = bufferConfig;
597     uint32_t txDescAddr, txDescTail;
598 
599     if (buffCfg == NULL)
600     {
601         return kStatus_InvalidArgument;
602     }
603 
604     /* Check the ring length. */
605     if (buffCfg->txRingLen < ENET_QOS_MIN_RINGLEN)
606     {
607         return kStatus_InvalidArgument;
608     }
609     /* Set the tx descriptor start/tail pointer, shall be word aligned. */
610     txDescAddr = (uint32_t)(uintptr_t)buffCfg->txDescStartAddrAlign & ENET_QOS_DMA_CHX_TXDESC_LIST_ADDR_TDESLA_MASK;
611     txDescTail = (uint32_t)(uintptr_t)buffCfg->txDescTailAddrAlign & ENET_QOS_DMA_CHX_TXDESC_TAIL_PTR_TDTP_MASK;
612 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
613     txDescAddr = MEMORY_ConvertMemoryMapAddress(txDescAddr, kMEMORY_Local2DMA);
614     txDescTail = MEMORY_ConvertMemoryMapAddress(txDescTail, kMEMORY_Local2DMA);
615 #endif
616     base->DMA_CH[channel].DMA_CHX_TXDESC_LIST_ADDR = txDescAddr;
617     base->DMA_CH[channel].DMA_CHX_TXDESC_TAIL_PTR  = txDescTail;
618     /* Set the tx ring length. */
619     base->DMA_CH[channel].DMA_CHX_TXDESC_RING_LENGTH =
620         ((uint32_t)buffCfg->txRingLen - 1U) & ENET_QOS_DMA_CHX_TXDESC_RING_LENGTH_TDRL_MASK;
621 
622     /* Init the txbdPtr to the transmit descriptor start address. */
623     txbdPtr = (enet_qos_tx_bd_struct_t *)(buffCfg->txDescStartAddrAlign);
624     for (j = 0; j < buffCfg->txRingLen; j++)
625     {
626         txbdPtr->buff1Addr   = 0;
627         txbdPtr->buff2Addr   = 0;
628         txbdPtr->buffLen     = control;
629         txbdPtr->controlStat = 0;
630         txbdPtr++;
631     }
632 
633     return kStatus_Success;
634 }
635 
ENET_QOS_RxDescriptorsInit(ENET_QOS_Type * base,enet_qos_config_t * config,const enet_qos_buffer_config_t * bufferConfig,bool intRxEnable,uint8_t channel)636 static status_t ENET_QOS_RxDescriptorsInit(ENET_QOS_Type *base,
637                                            enet_qos_config_t *config,
638                                            const enet_qos_buffer_config_t *bufferConfig,
639                                            bool intRxEnable,
640                                            uint8_t channel)
641 {
642     uint16_t j;
643     uint32_t reg;
644     enet_qos_rx_bd_struct_t *rxbdPtr;
645     uint16_t index;
646     bool doubleBuffEnable = ((config->specialControl & (uint32_t)kENET_QOS_DescDoubleBuffer) != 0U) ? true : false;
647     const enet_qos_buffer_config_t *buffCfg = bufferConfig;
648     uint32_t control                        = ENET_QOS_RXDESCRIP_RD_BUFF1VALID_MASK;
649     uint32_t rxDescAddr, rxDescTail;
650 
651     if (buffCfg == NULL)
652     {
653         return kStatus_InvalidArgument;
654     }
655 
656     if (intRxEnable)
657     {
658         control |= ENET_QOS_RXDESCRIP_RD_IOC_MASK;
659     }
660 
661     if (doubleBuffEnable)
662     {
663         control |= ENET_QOS_RXDESCRIP_RD_BUFF2VALID_MASK;
664     }
665 
666     /* Not give ownership to DMA before Rx buffer is ready */
667     if ((config->rxBuffAlloc == NULL) || (config->rxBuffFree == NULL))
668     {
669         control |= ENET_QOS_RXDESCRIP_WR_OWN_MASK;
670     }
671 
672     /* Check the ring length. */
673     if (buffCfg->rxRingLen < ENET_QOS_MIN_RINGLEN)
674     {
675         return kStatus_InvalidArgument;
676     }
677 
678     /* Set the rx descriptor start/tail pointer, shall be word aligned. */
679     rxDescAddr = (uint32_t)(uintptr_t)buffCfg->rxDescStartAddrAlign & ENET_QOS_DMA_CHX_RXDESC_LIST_ADDR_RDESLA_MASK;
680     rxDescTail = (uint32_t)(uintptr_t)buffCfg->rxDescTailAddrAlign & ENET_QOS_DMA_CHX_RXDESC_TAIL_PTR_RDTP_MASK;
681 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
682     rxDescAddr = MEMORY_ConvertMemoryMapAddress(rxDescAddr, kMEMORY_Local2DMA);
683     rxDescTail = MEMORY_ConvertMemoryMapAddress(rxDescTail, kMEMORY_Local2DMA);
684 #endif
685     base->DMA_CH[channel].DMA_CHX_RXDESC_LIST_ADDR = rxDescAddr;
686     base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR  = rxDescTail;
687     /* Register DMA_CHX_RXDESC_RING_LENGTH renamed to DMA_CHX_RX_CONTROL2 */
688 #if defined(ENET_QOS_DMA_CHX_RX_CONTROL2_COUNT) && ENET_QOS_DMA_CHX_RX_CONTROL2_COUNT
689     base->DMA_CH[channel].DMA_CHX_RX_CONTROL2 =
690         ((uint32_t)buffCfg->rxRingLen - 1U) & ENET_QOS_DMA_CHX_RX_CONTROL2_RDRL_MASK;
691 #else
692     base->DMA_CH[channel].DMA_CHX_RXDESC_RING_LENGTH =
693         ((uint32_t)buffCfg->rxRingLen - 1U) & ENET_QOS_DMA_CHX_RXDESC_RING_LENGTH_RDRL_MASK;
694 #endif
695     reg = base->DMA_CH[channel].DMA_CHX_RX_CTRL & ~ENET_QOS_DMA_CHX_RX_CTRL_RBSZ_13_y_MASK;
696     reg |= ENET_QOS_DMA_CHX_RX_CTRL_RBSZ_13_y(buffCfg->rxBuffSizeAlign >> ENET_QOS_RXBUFF_IGNORELSB_BITS);
697     base->DMA_CH[channel].DMA_CHX_RX_CTRL = reg;
698 
699     /* Init the rxbdPtr to the receive descriptor start address. */
700     rxbdPtr = (enet_qos_rx_bd_struct_t *)(buffCfg->rxDescStartAddrAlign);
701     for (j = 0U; j < buffCfg->rxRingLen; j++)
702     {
703         if ((config->rxBuffAlloc == NULL) || (config->rxBuffFree == NULL))
704         {
705             if (doubleBuffEnable)
706             {
707                 index = 2U * j;
708             }
709             else
710             {
711                 index = j;
712             }
713 
714 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
715             buffCfg->rxBufferStartAddr[index] =
716                 MEMORY_ConvertMemoryMapAddress((uintptr_t)buffCfg->rxBufferStartAddr[index], kMEMORY_Local2DMA);
717 #endif
718             rxbdPtr->buff1Addr = buffCfg->rxBufferStartAddr[index];
719 
720             /* The second buffer is set with 0 because it is not required for normal case. */
721             if (doubleBuffEnable)
722             {
723 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
724                 buffCfg->rxBufferStartAddr[index + 1U] = MEMORY_ConvertMemoryMapAddress(
725                     (uintptr_t)buffCfg->rxBufferStartAddr[index + 1U], kMEMORY_Local2DMA);
726 #endif
727                 rxbdPtr->buff2Addr = buffCfg->rxBufferStartAddr[index + 1U];
728             }
729             else
730             {
731                 rxbdPtr->buff2Addr = 0;
732             }
733         }
734 
735         /* Set the valid and DMA own flag.*/
736         rxbdPtr->control = control;
737         rxbdPtr++;
738     }
739 
740     return kStatus_Success;
741 }
742 
ENET_QOS_SetPtp1588(ENET_QOS_Type * base,const enet_qos_config_t * config,uint32_t refClk_Hz)743 static status_t ENET_QOS_SetPtp1588(ENET_QOS_Type *base, const enet_qos_config_t *config, uint32_t refClk_Hz)
744 {
745     assert(config != NULL);
746     assert(config->ptpConfig != NULL);
747     assert(refClk_Hz != 0U);
748 
749     uint32_t control                 = 0U;
750     status_t result                  = kStatus_Success;
751     enet_qos_ptp_config_t *ptpConfig = config->ptpConfig;
752     uint32_t ptpClk_Hz               = refClk_Hz;
753     uint32_t ssInc, snsSinc;
754 
755     /* Clear the timestamp interrupt first. */
756     base->MAC_INTERRUPT_ENABLE &= ~ENET_QOS_MAC_INTERRUPT_ENABLE_TSIE_MASK;
757 
758     if (ptpConfig->fineUpdateEnable)
759     {
760         control |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCFUPDT_MASK;
761         ptpClk_Hz = ptpConfig->systemTimeClock_Hz; /* PTP clock 50MHz. */
762     }
763 
764     /* Enable the IEEE 1588 timestamping and snapshot for event message. */
765     control |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_TSIPV4ENA_MASK |
766                ENET_QOS_MAC_TIMESTAMP_CONTROL_TSIPV6ENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_TSENALL_MASK |
767                ENET_QOS_MAC_TIMESTAMP_CONTROL_TSEVNTENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_SNAPTYPSEL_MASK |
768                ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR(ptpConfig->tsRollover);
769 
770     if (ptpConfig->ptp1588V2Enable)
771     {
772         control |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSVER2ENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_TSIPENA_MASK;
773     }
774 
775     /* Initialize the sub-second increment register. */
776     if (ptpConfig->tsRollover == kENET_QOS_DigitalRollover)
777     {
778         ssInc = (uint32_t)(((uint64_t)ENET_QOS_NANOSECS_ONESECOND << 8U) / ptpClk_Hz);
779     }
780     else
781     {
782         ssInc = (uint32_t)((((uint64_t)ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_TSSS_MASK + 1U) << 8U) / ptpClk_Hz);
783     }
784 
785     snsSinc = ssInc & 0xFFU;
786     ssInc   = (ssInc >> 8U) & 0xFFU;
787 
788     base->MAC_TIMESTAMP_CONTROL = control;
789 
790     /* Initialize the system timer. */
791     base->MAC_SYSTEM_TIME_NANOSECONDS_UPDATE = 0;
792 
793     /* Set the second.*/
794     base->MAC_SYSTEM_TIME_SECONDS_UPDATE      = 0;
795     base->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS = 0;
796 
797     /* Initialize the system timer. */
798     base->MAC_TIMESTAMP_CONTROL |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSINIT_MASK;
799 
800     while ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSINIT_MASK) != 0U)
801     {
802     }
803 
804     base->MAC_SUB_SECOND_INCREMENT =
805         ENET_QOS_MAC_SUB_SECOND_INCREMENT_SSINC(ssInc) | ENET_QOS_MAC_SUB_SECOND_INCREMENT_SNSINC(snsSinc);
806 
807     /* Set the initial added value for the fine update. */
808     if (ptpConfig->fineUpdateEnable)
809     {
810         result = ENET_QOS_Ptp1588CorrectTimerInFine(base, ptpConfig->defaultAddend);
811     }
812 
813     return result;
814 }
815 
ENET_QOS_TxDirtyRingAvailable(enet_qos_tx_dirty_ring_t * txDirtyRing)816 static inline bool ENET_QOS_TxDirtyRingAvailable(enet_qos_tx_dirty_ring_t *txDirtyRing)
817 {
818     return !txDirtyRing->isFull;
819 }
820 
ENET_QOS_StoreRxFrameTime(ENET_QOS_Type * base,enet_qos_handle_t * handle,enet_qos_rx_bd_struct_t * rxDesc,enet_qos_ptp_time_t * ts)821 static void ENET_QOS_StoreRxFrameTime(ENET_QOS_Type *base,
822                                       enet_qos_handle_t *handle,
823                                       enet_qos_rx_bd_struct_t *rxDesc,
824                                       enet_qos_ptp_time_t *ts)
825 {
826     assert(ts != NULL);
827 
828     uint32_t nanosecond;
829 
830     /* Get transmit time stamp second. */
831     nanosecond = rxDesc->buff1Addr;
832     if ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK) == 0U)
833     {
834         /* Binary rollover, 0.465ns accuracy. */
835         nanosecond = (uint32_t)(((uint64_t)nanosecond * 465U) / 1000U);
836     }
837     ts->second     = rxDesc->reserved;
838     ts->nanosecond = nanosecond;
839 }
840 
ENET_QOS_IsMIIConfigValid(enet_qos_mii_mode_t mode,enet_qos_mii_speed_t speed)841 static inline bool ENET_QOS_IsMIIConfigValid(enet_qos_mii_mode_t mode, enet_qos_mii_speed_t speed)
842 {
843     /* Errata ERR050539: ENET_QOS does not support RMII 10Mbps mode */
844 #if defined(MIMXRT1171_SERIES) || defined(MIMXRT1172_SERIES) || defined(MIMXRT1173_cm7_SERIES) ||         \
845     defined(MIMXRT1173_cm4_SERIES) || defined(MIMXRT1175_cm7_SERIES) || defined(MIMXRT1175_cm4_SERIES) || \
846     defined(MIMXRT1176_cm7_SERIES) || defined(MIMXRT1176_cm4_SERIES)
847     if ((kENET_QOS_RmiiMode == mode) && (kENET_QOS_MiiSpeed10M == speed))
848     {
849         return false;
850     }
851 #endif /* MIMXRT117x_SERIES */
852 
853     return true;
854 }
855 
ENET_QOS_GetInstance(ENET_QOS_Type * base)856 uint32_t ENET_QOS_GetInstance(ENET_QOS_Type *base)
857 {
858     uint32_t instance;
859 
860     /* Find the instance index from base address mappings. */
861     for (instance = 0; instance < ARRAY_SIZE(s_enetqosBases); instance++)
862     {
863         if (s_enetqosBases[instance] == base)
864         {
865             break;
866         }
867     }
868 
869     assert(instance < ARRAY_SIZE(s_enetqosBases));
870 
871     return instance;
872 }
873 
874 /*!
875  * brief Gets the ENET default configuration structure.
876  *
877  * The purpose of this API is to get the default ENET configure
878  * structure for ENET_QOS_Init(). User may use the initialized
879  * structure unchanged in ENET_QOS_Init(), or modify some fields of the
880  * structure before calling ENET_QOS_Init().
881  * Example:
882    code
883    enet_qos_config_t config;
884    ENET_QOS_GetDefaultConfig(&config);
885    endcode
886  * param config The ENET mac controller configuration structure pointer.
887  */
ENET_QOS_GetDefaultConfig(enet_qos_config_t * config)888 void ENET_QOS_GetDefaultConfig(enet_qos_config_t *config)
889 {
890     /* Checks input parameter. */
891     assert(config != NULL);
892 
893     /* Initializes the configure structure to zero. */
894     (void)memset(config, 0, sizeof(*config));
895 
896     /* Sets RGMII mode, full duplex, 1000Mbps for MAC and PHY data interface. */
897     config->miiMode   = kENET_QOS_RgmiiMode;
898     config->miiSpeed  = kENET_QOS_MiiSpeed1000M;
899     config->miiDuplex = kENET_QOS_MiiFullDuplex;
900 
901     /* Sets default configuration for other options. */
902     config->specialControl = 0;
903     config->multiqueueCfg  = NULL;
904     config->pauseDuration  = 0;
905 
906     config->ptpConfig = NULL;
907 }
908 
909 /*!
910  * brief Initializes the ENET module.
911  *
912  * This function set up the with ENET basic configuration.
913  *
914  * param base    ENET peripheral base address.
915  * param config  ENET mac configuration structure pointer.
916  *        The "enet_qos_config_t" type mac configuration return from ENET_QOS_GetDefaultConfig
917  *        can be used directly. It is also possible to verify the Mac configuration using other methods.
918  * param macAddr  ENET mac address of Ethernet device. This MAC address should be
919  *        provided.
920  * param refclkSrc_Hz ENET input reference clock.
921  */
ENET_QOS_Up(ENET_QOS_Type * base,const enet_qos_config_t * config,uint8_t * macAddr,uint8_t macCount,uint32_t refclkSrc_Hz)922 status_t ENET_QOS_Up(
923     ENET_QOS_Type *base, const enet_qos_config_t *config, uint8_t *macAddr, uint8_t macCount, uint32_t refclkSrc_Hz)
924 {
925     assert(config != NULL);
926     status_t result;
927 
928     /* Initializes the ENET MDIO. */
929     ENET_QOS_SetSMI(base, refclkSrc_Hz);
930 
931     /* Initializes the ENET MTL with basic function. */
932     ENET_QOS_SetMTL(base, config);
933 
934     /* Initializes the ENET MAC with basic function. */
935     result = ENET_QOS_SetMacControl(base, config, macAddr, macCount);
936 
937     return result;
938 }
939 
940 /*!
941  * brief Initializes the ENET module.
942  *
943  * This function ungates the module clock and initializes it with the ENET basic
944  * configuration.
945  *
946  * param base    ENET peripheral base address.
947  * param config  ENET mac configuration structure pointer.
948  *        The "enet_qos_config_t" type mac configuration return from ENET_QOS_GetDefaultConfig
949  *        can be used directly. It is also possible to verify the Mac configuration using other methods.
950  * param macAddr  ENET mac address of Ethernet device. This MAC address should be
951  *        provided.
952  * param refclkSrc_Hz ENET input reference clock.
953  */
ENET_QOS_Init(ENET_QOS_Type * base,const enet_qos_config_t * config,uint8_t * macAddr,uint8_t macCount,uint32_t refclkSrc_Hz)954 status_t ENET_QOS_Init(
955     ENET_QOS_Type *base, const enet_qos_config_t *config, uint8_t *macAddr, uint8_t macCount, uint32_t refclkSrc_Hz)
956 {
957     assert(config != NULL);
958 
959     status_t result = kStatus_Success;
960 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
961     uint32_t instance = ENET_QOS_GetInstance(base);
962 
963     /* Ungate ENET clock. */
964     (void)CLOCK_EnableClock(s_enetqosClock[instance]);
965 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
966 
967     /* Initializes the ENET DMA with basic function. */
968     result = ENET_QOS_SetDMAControl(base, config);
969     if (result != kStatus_Success)
970     {
971         return result;
972     }
973 
974     result = ENET_QOS_Up(base, config, macAddr, macCount, refclkSrc_Hz);
975     if (result != kStatus_Success)
976     {
977         return result;
978     }
979 
980     if (config->ptpConfig != NULL)
981     {
982         result = ENET_QOS_SetPtp1588(base, config, refclkSrc_Hz);
983     }
984 
985     return result;
986 }
987 
988 /*!
989  * brief Stops the ENET module.
990 
991  * This function disables the ENET module.
992  *
993  * param base  ENET peripheral base address.
994  */
ENET_QOS_Down(ENET_QOS_Type * base)995 void ENET_QOS_Down(ENET_QOS_Type *base)
996 {
997     enet_qos_handle_t *handle = s_ENETHandle[ENET_QOS_GetInstance(base)];
998     enet_qos_tx_bd_struct_t *txbdPtr;
999     uint8_t index;
1000     uint32_t primask, j;
1001     uint32_t txDescAddr;
1002 
1003     /* Disable all interrupts */
1004     ENET_QOS_DisableInterrupts(base, 0xFF);
1005 
1006     for (index = 0; index < handle->txQueueUse; index++)
1007     {
1008         enet_qos_tx_bd_ring_t *txBdRing       = &handle->txBdRing[index];
1009         enet_qos_tx_dirty_ring_t *txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[index];
1010 
1011         /* Clear pending descriptors */
1012         if (handle->callback != NULL)
1013         {
1014             while (txBdRing->txDescUsed > 0U)
1015             {
1016                 enet_qos_frame_info_t *txDirty = &txDirtyRing->txDirtyBase[txDirtyRing->txConsumIdx];
1017 
1018                 txDirty->isTsAvail = false;
1019 
1020                 handle->callback(base, handle, kENET_QOS_TxIntEvent, index, handle->userData);
1021 
1022                 primask = DisableGlobalIRQ();
1023                 txBdRing->txDescUsed--;
1024                 EnableGlobalIRQ(primask);
1025             }
1026         }
1027 
1028         /* Disable Tx DMA */
1029         base->DMA_CH[index].DMA_CHX_TX_CTRL &= ~ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK;
1030 
1031         /* Flush Tx Queue */
1032         base->MTL_QUEUE[index].MTL_TXQX_OP_MODE |= ENET_QOS_MTL_TXQX_OP_MODE_FTQ_MASK;
1033 
1034         /* Wait until Tx Queue is empty */
1035         while ((base->MTL_QUEUE[index].MTL_TXQX_DBG &
1036                 (ENET_QOS_MTL_TXQX_DBG_TXQSTS_MASK | ENET_QOS_MTL_TXQX_DBG_PTXQ_MASK)) != 0U)
1037         {
1038         }
1039 
1040         /* Reset hardware ring buffer */
1041         txDescAddr =
1042             (uint32_t)(uintptr_t)handle->txBdRing[index].txBdBase & ENET_QOS_DMA_CHX_TXDESC_LIST_ADDR_TDESLA_MASK;
1043 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
1044         txDescAddr = MEMORY_ConvertMemoryMapAddress(txDescAddr, kMEMORY_Local2DMA);
1045 #endif
1046         base->DMA_CH[index].DMA_CHX_TXDESC_LIST_ADDR = txDescAddr;
1047 
1048         /* Reset software ring buffer */
1049         handle->txBdRing[index].txGenIdx    = 0;
1050         handle->txBdRing[index].txConsumIdx = 0;
1051         handle->txBdRing[index].txDescUsed  = 0;
1052 
1053         handle->txDirtyRing[index].txGenIdx    = 0;
1054         handle->txDirtyRing[index].txConsumIdx = 0;
1055         handle->txDirtyRing[index].isFull      = false;
1056 
1057         txbdPtr = (enet_qos_tx_bd_struct_t *)(handle->txBdRing[index].txBdBase);
1058         for (j = 0; j < handle->txBdRing[index].txRingLen; j++)
1059         {
1060             txbdPtr->buff1Addr   = 0;
1061             txbdPtr->buff2Addr   = 0;
1062             txbdPtr->buffLen     = 0;
1063             txbdPtr->controlStat = 0;
1064             txbdPtr++;
1065         }
1066     }
1067 
1068     /* Disable MAC Rx/Tx */
1069     base->MAC_CONFIGURATION &= ~(ENET_QOS_MAC_CONFIGURATION_TE_MASK | ENET_QOS_MAC_CONFIGURATION_RE_MASK);
1070 
1071     /* Disable Rx DMA */
1072     for (index = 0; index < handle->rxQueueUse; index++)
1073     {
1074         base->DMA_CH[index].DMA_CHX_RX_CTRL &= ~ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;
1075     }
1076 }
1077 
1078 /*!
1079  * brief Deinitializes the ENET module.
1080 
1081  * This function gates the module clock and disables the ENET module.
1082  *
1083  * param base  ENET peripheral base address.
1084  */
ENET_QOS_Deinit(ENET_QOS_Type * base)1085 void ENET_QOS_Deinit(ENET_QOS_Type *base)
1086 {
1087     /* Reset first and wait for the complete
1088      * The reset bit will automatically be cleared after complete. */
1089     base->DMA_MODE |= ENET_QOS_DMA_MODE_SWR_MASK;
1090     while ((base->DMA_MODE & ENET_QOS_DMA_MODE_SWR_MASK) != 0U)
1091     {
1092     }
1093 
1094 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
1095     /* Disables the clock source. */
1096     (void)CLOCK_DisableClock(s_enetqosClock[ENET_QOS_GetInstance(base)]);
1097 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
1098 }
1099 
1100 /*!
1101  * brief Initialize for all ENET descriptors.
1102  *
1103  * note This function is do all tx/rx descriptors initialization. Because this API
1104  *  read all interrupt registers first and then set the interrupt flag for all descriptos,
1105  * if the interrupt register is set. so the descriptor initialization should be called
1106  * after ENET_QOS_Init(), ENET_QOS_EnableInterrupts() and ENET_QOS_CreateHandler()(if transactional APIs
1107  * are used).
1108  *
1109  * param base  ENET peripheral base address.
1110  * param config The configuration for ENET.
1111  * param bufferConfig All buffers configuration.
1112  */
ENET_QOS_DescriptorInit(ENET_QOS_Type * base,enet_qos_config_t * config,enet_qos_buffer_config_t * bufferConfig)1113 status_t ENET_QOS_DescriptorInit(ENET_QOS_Type *base, enet_qos_config_t *config, enet_qos_buffer_config_t *bufferConfig)
1114 {
1115     assert(config != NULL);
1116     assert(bufferConfig != NULL);
1117 
1118     bool intTxEnable   = false;
1119     bool intRxEnable   = false;
1120     uint8_t ringNum    = 1;
1121     uint8_t txQueueUse = 1;
1122     uint8_t rxQueueUse = 1;
1123     uint8_t channel;
1124 
1125     if (config->multiqueueCfg != NULL)
1126     {
1127         ringNum    = MAX(config->multiqueueCfg->txQueueUse, config->multiqueueCfg->rxQueueUse);
1128         txQueueUse = config->multiqueueCfg->txQueueUse;
1129         rxQueueUse = config->multiqueueCfg->rxQueueUse;
1130     }
1131 
1132     for (channel = 0; channel < ringNum; channel++)
1133     {
1134         intRxEnable = ((base->DMA_CH[channel].DMA_CHX_INT_EN & ENET_QOS_DMA_CHX_INT_EN_RIE_MASK) != 0U) ? true : false;
1135         intTxEnable = ((base->DMA_CH[channel].DMA_CHX_INT_EN & ENET_QOS_DMA_CHX_INT_EN_TIE_MASK) != 0U) ? true : false;
1136 
1137         if (channel < txQueueUse)
1138         {
1139             if ((ENET_QOS_TxDescriptorsInit(base, bufferConfig, intTxEnable, channel) != kStatus_Success))
1140             {
1141                 return kStatus_Fail;
1142             }
1143         }
1144 
1145         if (channel < rxQueueUse)
1146         {
1147             if ((ENET_QOS_RxDescriptorsInit(base, config, bufferConfig, intRxEnable, channel) != kStatus_Success))
1148             {
1149                 return kStatus_Fail;
1150             }
1151         }
1152 
1153         bufferConfig++;
1154     }
1155     return kStatus_Success;
1156 }
1157 
1158 /*!
1159  * brief Allocates Rx buffers for all BDs.
1160  * It's used for zero copy Rx. In zero copy Rx case, Rx buffers are dynamic. This function
1161  * will populate initial buffers in all BDs for receiving. Then ENET_QOS_GetRxFrame() is used
1162  * to get Rx frame with zero copy, it will allocate new buffer to replace the buffer in BD taken
1163  * by application application should free those buffers after they're used.
1164  *
1165  * note This function should be called after ENET_QOS_CreateHandler() and buffer allocating callback
1166  * function should be ready.
1167  *
1168  * param base  ENET_QOS peripheral base address.
1169  * param handle The ENET_QOS handler structure. This is the same handler pointer used in the ENET_QOS_Init.
1170  */
ENET_QOS_RxBufferAllocAll(ENET_QOS_Type * base,enet_qos_handle_t * handle)1171 status_t ENET_QOS_RxBufferAllocAll(ENET_QOS_Type *base, enet_qos_handle_t *handle)
1172 {
1173     status_t result = kStatus_Success;
1174     enet_qos_rx_bd_struct_t *rxbdPtr;
1175     uint32_t buffAddr;
1176     uint8_t channel;
1177     uint16_t index;
1178     uint16_t j;
1179 
1180     if ((handle->rxBuffAlloc == NULL) || (handle->rxBuffFree == NULL))
1181     {
1182         return kStatus_ENET_QOS_InitMemoryFail;
1183     }
1184 
1185     for (channel = 0; channel < handle->rxQueueUse; channel++)
1186     {
1187         /* Init the rxbdPtr to the receive descriptor start address. */
1188         rxbdPtr = handle->rxBdRing[channel].rxBdBase;
1189         for (j = 0U; j < handle->rxBdRing[channel].rxRingLen; j++)
1190         {
1191             if (handle->doubleBuffEnable)
1192             {
1193                 index = 2U * j;
1194             }
1195             else
1196             {
1197                 index = j;
1198             }
1199 
1200             buffAddr = (uint32_t)(uintptr_t)(uint8_t *)handle->rxBuffAlloc(base, handle->userData, channel);
1201             if (buffAddr == 0U)
1202             {
1203                 result = kStatus_ENET_QOS_InitMemoryFail;
1204                 break;
1205             }
1206 
1207 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
1208             buffAddr = (uint32_t)MEMORY_ConvertMemoryMapAddress(buffAddr, kMEMORY_Local2DMA);
1209 #endif
1210             rxbdPtr->buff1Addr                        = buffAddr;
1211             handle->rxBufferStartAddr[channel][index] = buffAddr;
1212 
1213             /* The second buffer is set with 0 because it is not required for normal case. */
1214             if (handle->doubleBuffEnable)
1215             {
1216                 buffAddr = (uint32_t)(uintptr_t)(uint8_t *)handle->rxBuffAlloc(base, handle->userData, channel);
1217                 if (buffAddr == 0U)
1218                 {
1219                     result = kStatus_ENET_QOS_InitMemoryFail;
1220                     break;
1221                 }
1222 
1223 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
1224                 buffAddr = (uint32_t)MEMORY_ConvertMemoryMapAddress(buffAddr, kMEMORY_Local2DMA);
1225 #endif
1226                 rxbdPtr->buff2Addr                             = buffAddr;
1227                 handle->rxBufferStartAddr[channel][index + 1U] = buffAddr;
1228             }
1229             else
1230             {
1231                 rxbdPtr->buff2Addr = 0;
1232             }
1233 
1234             /* Set the valid and DMA own flag.*/
1235             rxbdPtr->control |= ENET_QOS_RXDESCRIP_WR_OWN_MASK;
1236             rxbdPtr++;
1237         }
1238     }
1239 
1240     if (result == kStatus_ENET_QOS_InitMemoryFail)
1241     {
1242         ENET_QOS_RxBufferFreeAll(base, handle);
1243     }
1244 
1245     return result;
1246 }
1247 
1248 /*!
1249  * brief Frees Rx buffers in all BDs.
1250  * It's used for zero copy Rx. In zero copy Rx case, Rx buffers are dynamic. This function
1251  * will free left buffers in all BDs.
1252  *
1253  * param base  ENET_QOS peripheral base address.
1254  * param handle The ENET_QOS handler structure. This is the same handler pointer used in the ENET_QOS_Init.
1255  */
ENET_QOS_RxBufferFreeAll(ENET_QOS_Type * base,enet_qos_handle_t * handle)1256 void ENET_QOS_RxBufferFreeAll(ENET_QOS_Type *base, enet_qos_handle_t *handle)
1257 {
1258     uint32_t buffAddr;
1259     uint8_t channel;
1260     uint16_t index;
1261     uint16_t j;
1262 
1263     if (handle->rxBuffFree != NULL)
1264     {
1265         for (channel = 0; channel < handle->rxQueueUse; channel++)
1266         {
1267             for (j = 0U; j < handle->rxBdRing[channel].rxRingLen; j++)
1268             {
1269                 if (handle->doubleBuffEnable)
1270                 {
1271                     index = 2U * j;
1272                 }
1273                 else
1274                 {
1275                     index = j;
1276                 }
1277 
1278 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
1279                 buffAddr = MEMORY_ConvertMemoryMapAddress((uintptr_t)handle->rxBufferStartAddr[channel][index],
1280                                                           kMEMORY_DMA2Local);
1281 #else
1282                 buffAddr = (uint32_t)handle->rxBufferStartAddr[channel][index];
1283 #endif
1284                 if (buffAddr != 0U)
1285                 {
1286                     handle->rxBuffFree(base, (void *)(uint8_t *)(uintptr_t)buffAddr, handle->userData, channel);
1287                 }
1288 
1289                 /* The second buffer is set with 0 because it is not required for normal case. */
1290                 if (handle->doubleBuffEnable)
1291                 {
1292 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
1293                     buffAddr = MEMORY_ConvertMemoryMapAddress((uintptr_t)handle->rxBufferStartAddr[channel][index + 1U],
1294                                                               kMEMORY_DMA2Local);
1295 #else
1296                     buffAddr = (uint32_t)handle->rxBufferStartAddr[channel][index + 1U];
1297 #endif
1298                     if (buffAddr != 0U)
1299                     {
1300                         handle->rxBuffFree(base, (void *)(uint8_t *)(uintptr_t)buffAddr, handle->userData, channel);
1301                     }
1302                 }
1303             }
1304         }
1305     }
1306 }
1307 
1308 /*!
1309  * brief Starts the ENET rx/tx.
1310  *  This function enable the tx/rx and starts the rx/tx DMA.
1311  * This shall be set after ENET initialization and before
1312  * starting to receive the data.
1313  *
1314  * param base  ENET peripheral base address.
1315  * param rxRingNum  The number of the used rx rings. It shall not be
1316  * larger than the ENET_QOS_RING_NUM_MAX(2). If the ringNum is set with
1317  * 1, the ring 0 will be used.
1318  * param txRingNum  The number of the used tx rings. It shall not be
1319  * larger than the ENET_QOS_RING_NUM_MAX(2). If the ringNum is set with
1320  * 1, the ring 0 will be used.
1321  *
1322  * note This must be called after all the ENET initilization.
1323  * And should be called when the ENET receive/transmit is required.
1324  */
ENET_QOS_StartRxTx(ENET_QOS_Type * base,uint8_t txRingNum,uint8_t rxRingNum)1325 void ENET_QOS_StartRxTx(ENET_QOS_Type *base, uint8_t txRingNum, uint8_t rxRingNum)
1326 {
1327     assert(txRingNum != 0U);
1328     assert(rxRingNum != 0U);
1329 
1330     uint8_t index;
1331 
1332     if (txRingNum > ENET_QOS_RING_NUM_MAX)
1333     {
1334         txRingNum = ENET_QOS_RING_NUM_MAX;
1335     }
1336     if (rxRingNum > ENET_QOS_RING_NUM_MAX)
1337     {
1338         rxRingNum = ENET_QOS_RING_NUM_MAX;
1339     }
1340     /* Start/Acive the DMA first. */
1341     for (index = 0; index < rxRingNum; index++)
1342     {
1343         base->DMA_CH[index].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;
1344     }
1345     for (index = 0; index < txRingNum; index++)
1346     {
1347         base->DMA_CH[index].DMA_CHX_TX_CTRL |= ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK;
1348     }
1349 
1350     /* Enable the RX and TX at same time. */
1351     base->MAC_CONFIGURATION |= (ENET_QOS_MAC_CONFIGURATION_TE_MASK | ENET_QOS_MAC_CONFIGURATION_RE_MASK);
1352 }
1353 
1354 /*!
1355  * brief Enables the ENET DMA and MAC interrupts.
1356  *
1357  * This function enables the ENET interrupt according to the provided mask. The mask
1358  * is a logical OR of enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t.
1359  * For example, to enable the dma and mac interrupt, do the following.
1360  * code
1361  *     ENET_QOS_EnableInterrupts(ENET, kENET_QOS_DmaRx | kENET_QOS_DmaTx | kENET_QOS_MacPmt);
1362  * endcode
1363  *
1364  * param base  ENET peripheral base address.
1365  * param mask  ENET interrupts to enable. This is a logical OR of both
1366  *             enumeration :: enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t.
1367  */
ENET_QOS_EnableInterrupts(ENET_QOS_Type * base,uint32_t mask)1368 void ENET_QOS_EnableInterrupts(ENET_QOS_Type *base, uint32_t mask)
1369 {
1370     uint32_t interrupt = mask & 0xFFFFU;
1371     uint8_t index;
1372 
1373     /* For dma interrupt. */
1374     if (interrupt != 0U)
1375     {
1376         for (index = 0; index < ENET_QOS_RING_NUM_MAX; index++)
1377         {
1378             /* Set for all abnormal interrupts. */
1379             if ((ENET_QOS_ABNORM_INT_MASK & interrupt) != 0U)
1380             {
1381                 interrupt |= ENET_QOS_DMA_CHX_INT_EN_AIE_MASK;
1382             }
1383             /* Set for all normal interrupts. */
1384             if ((ENET_QOS_NORM_INT_MASK & interrupt) != 0U)
1385             {
1386                 interrupt |= ENET_QOS_DMA_CHX_INT_EN_NIE_MASK;
1387             }
1388             base->DMA_CH[index].DMA_CHX_INT_EN = interrupt;
1389         }
1390     }
1391     interrupt = mask >> ENET_QOS_MACINT_ENUM_OFFSET;
1392     if (interrupt != 0U)
1393     {
1394         /* MAC interrupt */
1395         base->MAC_INTERRUPT_ENABLE |= interrupt;
1396     }
1397 }
1398 
1399 /*!
1400  * brief Clears the ENET mac interrupt events status flag.
1401  *
1402  * This function clears enabled ENET interrupts according to the provided mask. The mask
1403  * is a logical OR of enumeration members. See the ref enet_qos_mac_interrupt_enable_t.
1404  * For example, to clear the TX frame interrupt and RX frame interrupt, do the following.
1405  * code
1406  *     ENET_QOS_ClearMacInterruptStatus(ENET, kENET_QOS_MacPmt);
1407  * endcode
1408  *
1409  * param base  ENET peripheral base address.
1410  * param mask  ENET interrupt source to be cleared.
1411  * This is the logical OR of members of the enumeration :: enet_qos_mac_interrupt_enable_t.
1412  */
ENET_QOS_ClearMacInterruptStatus(ENET_QOS_Type * base,uint32_t mask)1413 void ENET_QOS_ClearMacInterruptStatus(ENET_QOS_Type *base, uint32_t mask)
1414 {
1415     volatile uint32_t dummy;
1416 
1417     if ((mask & (uint32_t)kENET_QOS_MacTimestamp) != 0U)
1418     {
1419         dummy = base->MAC_TIMESTAMP_STATUS;
1420     }
1421     else if ((mask & (uint32_t)kENET_QOS_MacPmt) != 0U)
1422     {
1423         dummy = base->MAC_PMT_CONTROL_STATUS;
1424     }
1425     else
1426     {
1427         /* Add for avoid the misra 2004 rule 14.10 */
1428     }
1429     (void)dummy;
1430 }
1431 
1432 /*!
1433  * brief Disables the ENET DMA and MAC interrupts.
1434  *
1435  * This function disables the ENET interrupt according to the provided mask. The mask
1436  * is a logical OR of enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t.
1437  * For example, to disable the dma and mac interrupt, do the following.
1438  * code
1439  *     ENET_QOS_DisableInterrupts(ENET, kENET_QOS_DmaRx | kENET_QOS_DmaTx | kENET_QOS_MacPmt);
1440  * endcode
1441  *
1442  * param base  ENET peripheral base address.
1443  * param mask  ENET interrupts to disables. This is a logical OR of both
1444  *             enumeration :: enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t.
1445  */
ENET_QOS_DisableInterrupts(ENET_QOS_Type * base,uint32_t mask)1446 void ENET_QOS_DisableInterrupts(ENET_QOS_Type *base, uint32_t mask)
1447 {
1448     uint32_t interrupt = mask & 0xFFFFU;
1449     uint8_t index;
1450 
1451     /* For dma interrupt. */
1452     if (interrupt != 0U)
1453     {
1454         for (index = 0; index < ENET_QOS_RING_NUM_MAX; index++)
1455         {
1456             /* Set for all abnormal interrupts. */
1457             if ((ENET_QOS_ABNORM_INT_MASK & interrupt) != 0U)
1458             {
1459                 interrupt |= ENET_QOS_DMA_CHX_INT_EN_AIE_MASK;
1460             }
1461             /* Set for all normal interrupts. */
1462             if ((ENET_QOS_NORM_INT_MASK & interrupt) != 0U)
1463             {
1464                 interrupt |= ENET_QOS_DMA_CHX_INT_EN_NIE_MASK;
1465             }
1466             base->DMA_CH[index].DMA_CHX_INT_EN &= ~interrupt;
1467         }
1468     }
1469     interrupt = mask >> ENET_QOS_MACINT_ENUM_OFFSET;
1470     if (interrupt != 0U)
1471     {
1472         /* MAC interrupt */
1473         base->MAC_INTERRUPT_ENABLE &= ~interrupt;
1474     }
1475 }
1476 
1477 /*!
1478  * @brief Set the second level IRQ handler, allow user to overwrite the default
1479  * second level weak IRQ handler.
1480  *
1481  * @param ISRHandler  he handler to install.
1482  */
ENET_QOS_SetISRHandler(ENET_QOS_Type * base,enet_qos_isr_t ISRHandler)1483 void ENET_QOS_SetISRHandler(ENET_QOS_Type *base, enet_qos_isr_t ISRHandler)
1484 {
1485     /* Update IRQ entry. */
1486     s_enetqosIsr = ISRHandler;
1487     /* Enable NVIC. */
1488     (void)EnableIRQ(s_enetqosIrqId[ENET_QOS_GetInstance(base)]);
1489 }
1490 
1491 /*!
1492  * brief Create ENET Handler
1493  *
1494  * This is a transactional API and it's provided to store all datas which are needed
1495  * during the whole transactional process. This API should not be used when you use
1496  * functional APIs to do data tx/rx. This is funtion will store many data/flag for
1497  * transactional use, so all configure API such as ENET_QOS_Init(), ENET_QOS_DescriptorInit(),
1498  * ENET_QOS_EnableInterrupts() etc.
1499  *
1500  * note as our transactional transmit API use the zero-copy transmit buffer.
1501  * so there are two thing we emphasize here:
1502  *  1. tx buffer free/requeue for application should be done in the tx
1503  *  interrupt handler. Please set callback: kENET_QOS_TxIntEvent with tx buffer free/requeue
1504  *  process APIs.
1505  *  2. the tx interrupt is forced to open.
1506  *
1507  * param base  ENET peripheral base address.
1508  * param handle ENET handler.
1509  * param config ENET configuration.
1510  * param bufferConfig ENET buffer configuration.
1511  * param callback The callback function.
1512  * param userData The application data.
1513  */
ENET_QOS_CreateHandler(ENET_QOS_Type * base,enet_qos_handle_t * handle,enet_qos_config_t * config,enet_qos_buffer_config_t * bufferConfig,enet_qos_callback_t callback,void * userData)1514 void ENET_QOS_CreateHandler(ENET_QOS_Type *base,
1515                             enet_qos_handle_t *handle,
1516                             enet_qos_config_t *config,
1517                             enet_qos_buffer_config_t *bufferConfig,
1518                             enet_qos_callback_t callback,
1519                             void *userData)
1520 {
1521     assert(config != NULL);
1522     assert(bufferConfig != NULL);
1523     assert(callback != NULL);
1524 
1525     uint8_t ringNum                      = 1;
1526     uint8_t count                        = 0;
1527     uint32_t rxIntEnable                 = 0;
1528     uint8_t txQueueUse                   = 1;
1529     uint8_t rxQueueUse                   = 1;
1530     enet_qos_buffer_config_t *buffConfig = bufferConfig;
1531 
1532     /* Store transfer parameters in handle pointer. */
1533     (void)memset(handle, 0, sizeof(enet_qos_handle_t));
1534 
1535     if (config->multiqueueCfg != NULL)
1536     {
1537         txQueueUse = config->multiqueueCfg->txQueueUse;
1538         rxQueueUse = config->multiqueueCfg->rxQueueUse;
1539         ringNum    = MAX(txQueueUse, rxQueueUse);
1540     }
1541 
1542     handle->txQueueUse = txQueueUse;
1543     handle->rxQueueUse = rxQueueUse;
1544 
1545     if ((config->specialControl & (uint32_t)kENET_QOS_DescDoubleBuffer) != 0U)
1546     {
1547         handle->doubleBuffEnable = true;
1548     }
1549 
1550     for (count = 0; count < ringNum; count++)
1551     {
1552         if (count < txQueueUse)
1553         {
1554             handle->txBdRing[count].txBdBase    = buffConfig->txDescStartAddrAlign;
1555             handle->txBdRing[count].txRingLen   = buffConfig->txRingLen;
1556             handle->txBdRing[count].txGenIdx    = 0;
1557             handle->txBdRing[count].txConsumIdx = 0;
1558             handle->txBdRing[count].txDescUsed  = 0;
1559 
1560             handle->txDirtyRing[count].txDirtyBase = buffConfig->txDirtyStartAddr;
1561             handle->txDirtyRing[count].txRingLen   = buffConfig->txRingLen;
1562             handle->txDirtyRing[count].txGenIdx    = 0;
1563             handle->txDirtyRing[count].txConsumIdx = 0;
1564 
1565             /* Enable tx interrupt for use transactional API to do tx buffer free/requeue. */
1566             base->DMA_CH[count].DMA_CHX_INT_EN |= ENET_QOS_DMA_CHX_INT_EN_TIE_MASK | ENET_QOS_DMA_CHX_INT_EN_NIE_MASK;
1567         }
1568 
1569         if (count < rxQueueUse)
1570         {
1571             handle->rxBdRing[count].rxBdBase        = buffConfig->rxDescStartAddrAlign;
1572             handle->rxBdRing[count].rxGenIdx        = 0;
1573             handle->rxBdRing[count].rxRingLen       = buffConfig->rxRingLen;
1574             handle->rxBdRing[count].rxBuffSizeAlign = buffConfig->rxBuffSizeAlign;
1575 
1576             /* Record rx buffer address for re-init Rx buffer descriptor */
1577             handle->rxBufferStartAddr[count] = buffConfig->rxBufferStartAddr;
1578 
1579             /* Record rx buffer need cache maintain */
1580             handle->rxMaintainEnable[count] = buffConfig->rxBuffNeedMaintain;
1581 
1582             /* Check if the rx interrrupt is enabled. */
1583             rxIntEnable |= (base->DMA_CH[count].DMA_CHX_INT_EN & ENET_QOS_DMA_CHX_INT_EN_RIE_MASK);
1584         }
1585 
1586         buffConfig++;
1587     }
1588 
1589     handle->rxintEnable = (rxIntEnable != 0U) ? true : false;
1590 
1591     /* Save the handle pointer in the global variables. */
1592     s_ENETHandle[ENET_QOS_GetInstance(base)] = handle;
1593 
1594     /* Set Rx alloc/free callback. */
1595     handle->rxBuffAlloc = config->rxBuffAlloc;
1596     handle->rxBuffFree  = config->rxBuffFree;
1597 
1598     /* Set callback and userData. */
1599     handle->callback = callback;
1600     handle->userData = userData;
1601 
1602     /* Use default ENET_QOS_CommonIRQHandler as default weak IRQ handler. */
1603     ENET_QOS_SetISRHandler(base, ENET_QOS_CommonIRQHandler);
1604 }
1605 
1606 /*!
1607  * brief Gets the ENET module Mac address.
1608  *
1609  * param base  ENET peripheral base address.
1610  * param macAddr The six-byte Mac address pointer.
1611  *        The pointer is allocated by application and input into the API.
1612  */
ENET_QOS_GetMacAddr(ENET_QOS_Type * base,uint8_t * macAddr,uint8_t index)1613 void ENET_QOS_GetMacAddr(ENET_QOS_Type *base, uint8_t *macAddr, uint8_t index)
1614 {
1615     assert(macAddr != NULL);
1616 
1617     uint32_t address = base->MAC_ADDRESS[index].LOW;
1618 
1619     /* Get from physical address lower register. */
1620     macAddr[2] = (uint8_t)(0xFFU & (address >> 24U));
1621     macAddr[3] = (uint8_t)(0xFFU & (address >> 16U));
1622     macAddr[4] = (uint8_t)(0xFFU & (address >> 8U));
1623     macAddr[5] = (uint8_t)(0xFFU & address);
1624 
1625     /* Get from physical address high register. */
1626     address    = base->MAC_ADDRESS[index].HIGH;
1627     macAddr[0] = (uint8_t)(0xFFU & (address >> 8U));
1628     macAddr[1] = (uint8_t)(0xFFU & address);
1629 }
1630 
1631 /*!
1632  * brief Adds the ENET_QOS device to a multicast group.
1633  *
1634  * param base    ENET_QOS peripheral base address.
1635  * param address The six-byte multicast group address which is provided by application.
1636  */
ENET_QOS_AddMulticastGroup(ENET_QOS_Type * base,uint8_t * address)1637 void ENET_QOS_AddMulticastGroup(ENET_QOS_Type *base, uint8_t *address)
1638 {
1639     assert(address != NULL);
1640 
1641     enet_qos_handle_t *handle = s_ENETHandle[ENET_QOS_GetInstance(base)];
1642     uint32_t crc              = 0xFFFFFFFFU;
1643     uint32_t count1           = 0;
1644     uint32_t count2           = 0;
1645 
1646     /* Calculates the CRC-32 polynomial on the multicast group address. */
1647     for (count1 = 0; count1 < 6U; count1++)
1648     {
1649         uint8_t c = address[count1];
1650         for (count2 = 0; count2 < 0x08U; count2++)
1651         {
1652             if (((c ^ crc) & 1U) != 0U)
1653             {
1654                 crc >>= 1U;
1655                 c >>= 1U;
1656                 crc ^= 0xEDB88320U;
1657             }
1658             else
1659             {
1660                 crc >>= 1U;
1661                 c >>= 1U;
1662             }
1663         }
1664     }
1665 
1666     /* Calculate bitwise reverse value. */
1667     crc = ENET_QOS_ReverseBits(~crc);
1668 
1669     /* Get highest 6 bits*/
1670     crc = crc >> 26U;
1671 
1672     handle->multicastCount[crc]++;
1673 
1674     if (0U != (crc & 0x20U))
1675     {
1676         base->MAC_HASH_TABLE_REG1 |= (1UL << (crc & 0x1FU));
1677     }
1678     else
1679     {
1680         base->MAC_HASH_TABLE_REG0 |= (1UL << (crc & 0x1FU));
1681     }
1682 }
1683 
1684 /*!
1685  * brief Moves the ENET_QOS device from a multicast group.
1686  *
1687  * param base  ENET_QOS peripheral base address.
1688  * param address The six-byte multicast group address which is provided by application.
1689  */
ENET_QOS_LeaveMulticastGroup(ENET_QOS_Type * base,uint8_t * address)1690 void ENET_QOS_LeaveMulticastGroup(ENET_QOS_Type *base, uint8_t *address)
1691 {
1692     assert(address != NULL);
1693 
1694     enet_qos_handle_t *handle = s_ENETHandle[ENET_QOS_GetInstance(base)];
1695     uint32_t crc              = 0xFFFFFFFFU;
1696     uint32_t count1           = 0;
1697     uint32_t count2           = 0;
1698 
1699     /* Calculates the CRC-32 polynomial on the multicast group address. */
1700     for (count1 = 0; count1 < 6U; count1++)
1701     {
1702         uint8_t c = address[count1];
1703         for (count2 = 0; count2 < 0x08U; count2++)
1704         {
1705             if (((c ^ crc) & 1U) != 0U)
1706             {
1707                 crc >>= 1U;
1708                 c >>= 1U;
1709                 crc ^= 0xEDB88320U;
1710             }
1711             else
1712             {
1713                 crc >>= 1U;
1714                 c >>= 1U;
1715             }
1716         }
1717     }
1718 
1719     /* Calculate bitwise reverse value. */
1720     crc = ENET_QOS_ReverseBits(~crc);
1721 
1722     /* Get highest 6 bits*/
1723     crc = crc >> 26U;
1724 
1725     handle->multicastCount[crc]--;
1726 
1727     /* Set the hash table if no collisions */
1728     if (0U == handle->multicastCount[crc])
1729     {
1730         if (0U != (crc & 0x20U))
1731         {
1732             base->MAC_HASH_TABLE_REG1 &= ~((1UL << (crc & 0x1FU)));
1733         }
1734         else
1735         {
1736             base->MAC_HASH_TABLE_REG0 &= ~((1UL << (crc & 0x1FU)));
1737         }
1738     }
1739 }
1740 
1741 /*!
1742  * brief Sets the ENET MII speed and duplex.
1743  *
1744  * This API is provided to dynamically change the speed and duplex for MAC.
1745  *
1746  * param base  ENET peripheral base address.
1747  * param speed The speed of the RMII mode.
1748  * param duplex The duplex of the RMII mode.
1749  * return kStatus_Success          The ENET MII speed and duplex has been set successfully.
1750  * return kStatus_InvalidArgument  Could not set the desired ENET MII speed and duplex combination.
1751  */
ENET_QOS_SetMII(ENET_QOS_Type * base,enet_qos_mii_speed_t speed,enet_qos_mii_duplex_t duplex)1752 status_t ENET_QOS_SetMII(ENET_QOS_Type *base, enet_qos_mii_speed_t speed, enet_qos_mii_duplex_t duplex)
1753 {
1754     uint32_t reg = base->MAC_CONFIGURATION & ~(ENET_QOS_MAC_CONFIGURATION_DM_MASK | ENET_QOS_MAC_CONFIGURATION_PS_MASK |
1755                                                ENET_QOS_MAC_CONFIGURATION_FES_MASK);
1756     enet_qos_mii_mode_t configured_mode = s_enetStates[ENET_QOS_GetInstance(base)].miiMode;
1757 
1758     if (!ENET_QOS_IsMIIConfigValid(configured_mode, speed))
1759     {
1760         return kStatus_InvalidArgument;
1761     }
1762 
1763     reg |= ENET_QOS_MAC_CONFIGURATION_DM(duplex) | (uint32_t)speed;
1764 
1765     base->MAC_CONFIGURATION = reg;
1766 
1767     return kStatus_Success;
1768 }
1769 
1770 /*!
1771  * brief Sets the ENET SMI(serial management interface)- MII management interface.
1772  *
1773  * param base  ENET peripheral base address.
1774  */
ENET_QOS_SetSMI(ENET_QOS_Type * base,uint32_t csrClock_Hz)1775 void ENET_QOS_SetSMI(ENET_QOS_Type *base, uint32_t csrClock_Hz)
1776 {
1777     uint32_t crDiv       = 0;
1778     uint32_t srcClock_Hz = csrClock_Hz / 1000000U;
1779 
1780     assert((srcClock_Hz >= 20U) && (srcClock_Hz < 800U));
1781 
1782     if (srcClock_Hz < 35U)
1783     {
1784         crDiv = 2;
1785     }
1786     else if (srcClock_Hz < 60U)
1787     {
1788         crDiv = 3;
1789     }
1790     else if (srcClock_Hz < 100U)
1791     {
1792         crDiv = 0;
1793     }
1794     else if (srcClock_Hz < 150U)
1795     {
1796         crDiv = 1;
1797     }
1798     else if (srcClock_Hz < 250U)
1799     {
1800         crDiv = 4;
1801     }
1802     else if (srcClock_Hz < 300U)
1803     {
1804         crDiv = 5;
1805     }
1806     else if (srcClock_Hz < 500U)
1807     {
1808         crDiv = 6;
1809     }
1810     else if (srcClock_Hz < 800U)
1811     {
1812         crDiv = 7;
1813     }
1814     else
1815     {
1816         /* Empty else */
1817     }
1818 
1819     base->MAC_MDIO_ADDRESS = ENET_QOS_MAC_MDIO_ADDRESS_CR(crDiv);
1820 }
1821 
1822 /*!
1823  * @brief Sends the MDIO IEEE802.3 Clause 22 format write command.
1824  * After send command, user needs to check whether the transmission is over
1825  * with ENET_QOS_IsSMIBusy().
1826  *
1827  * @param base  ENET peripheral base address.
1828  * @param phyAddr The PHY address.
1829  * @param regAddr The PHY register address.
1830  * @param data The data written to PHY.
1831  */
ENET_QOS_StartSMIWrite(ENET_QOS_Type * base,uint8_t phyAddr,uint8_t regAddr,uint16_t data)1832 void ENET_QOS_StartSMIWrite(ENET_QOS_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
1833 {
1834     uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK;
1835 
1836     /* Build MII write command. */
1837     base->MAC_MDIO_ADDRESS = reg | (uint32_t)kENET_QOS_MiiWriteFrame | ENET_QOS_MAC_MDIO_ADDRESS_PA(phyAddr) |
1838                              ENET_QOS_MAC_MDIO_ADDRESS_RDA(regAddr);
1839     base->MAC_MDIO_DATA = data;
1840     base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK;
1841 }
1842 
1843 /*!
1844  * @brief Sends the MDIO IEEE802.3 Clause 22 format read command.
1845  * After send command, user needs to check whether the transmission is over
1846  * with ENET_QOS_IsSMIBusy().
1847  *
1848  * @param base  ENET peripheral base address.
1849  * @param phyAddr The PHY address.
1850  * @param regAddr The PHY register address.
1851  */
ENET_QOS_StartSMIRead(ENET_QOS_Type * base,uint8_t phyAddr,uint8_t regAddr)1852 void ENET_QOS_StartSMIRead(ENET_QOS_Type *base, uint8_t phyAddr, uint8_t regAddr)
1853 {
1854     uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK;
1855 
1856     /* Build MII read command. */
1857     base->MAC_MDIO_ADDRESS = reg | (uint32_t)kENET_QOS_MiiReadFrame | ENET_QOS_MAC_MDIO_ADDRESS_PA(phyAddr) |
1858                              ENET_QOS_MAC_MDIO_ADDRESS_RDA(regAddr);
1859     base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK;
1860 }
1861 
1862 /*!
1863  * @brief Sends the MDIO IEEE802.3 Clause 45 format write command.
1864  * After send command, user needs to check whether the transmission is over
1865  * with ENET_QOS_IsSMIBusy().
1866  *
1867  * @param base  ENET peripheral base address.
1868  * @param portAddr  The MDIO port address(PHY address).
1869  * @param devAddr  The device address.
1870  * @param regAddr  The PHY register address.
1871  * @param data The data written to PHY.
1872  */
ENET_QOS_StartExtC45SMIWrite(ENET_QOS_Type * base,uint8_t portAddr,uint8_t devAddr,uint16_t regAddr,uint16_t data)1873 void ENET_QOS_StartExtC45SMIWrite(
1874     ENET_QOS_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t data)
1875 {
1876     uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK;
1877 
1878     /* Build MII write command. */
1879     base->MAC_MDIO_ADDRESS = reg | ENET_QOS_MAC_MDIO_ADDRESS_C45E_MASK | (uint32_t)kENET_QOS_MiiWriteFrame |
1880                              ENET_QOS_MAC_MDIO_ADDRESS_PA(portAddr) | ENET_QOS_MAC_MDIO_ADDRESS_RDA(devAddr);
1881     base->MAC_MDIO_DATA = data | ENET_QOS_MAC_MDIO_DATA_RA(regAddr);
1882     base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK;
1883 }
1884 
1885 /*!
1886  * @brief Sends the MDIO IEEE802.3 Clause 45 format read command.
1887  * After send command, user needs to check whether the transmission is over
1888  * with ENET_QOS_IsSMIBusy().
1889  *
1890  * @param base  ENET peripheral base address.
1891  * @param portAddr  The MDIO port address(PHY address).
1892  * @param devAddr  The device address.
1893  * @param regAddr  The PHY register address.
1894  */
ENET_QOS_StartExtC45SMIRead(ENET_QOS_Type * base,uint8_t portAddr,uint8_t devAddr,uint16_t regAddr)1895 void ENET_QOS_StartExtC45SMIRead(ENET_QOS_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr)
1896 {
1897     uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK;
1898 
1899     /* Build MII read command. */
1900     base->MAC_MDIO_ADDRESS = reg | ENET_QOS_MAC_MDIO_ADDRESS_C45E_MASK | (uint32_t)kENET_QOS_MiiReadFrame |
1901                              ENET_QOS_MAC_MDIO_ADDRESS_PA(portAddr) | ENET_QOS_MAC_MDIO_ADDRESS_RDA(devAddr);
1902     base->MAC_MDIO_DATA = ENET_QOS_MAC_MDIO_DATA_RA(regAddr);
1903     base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK;
1904 }
1905 
ENET_QOS_MDIOWaitTransferOver(ENET_QOS_Type * base)1906 static status_t ENET_QOS_MDIOWaitTransferOver(ENET_QOS_Type *base)
1907 {
1908     status_t result = kStatus_Success;
1909 #ifdef ENET_QOS_MDIO_TIMEOUT_COUNT
1910     uint32_t counter;
1911 #endif
1912 
1913 #ifdef ENET_QOS_MDIO_TIMEOUT_COUNT
1914     for (counter = ENET_QOS_MDIO_TIMEOUT_COUNT; counter > 0U; counter--)
1915     {
1916         if (!ENET_QOS_IsSMIBusy(base))
1917         {
1918             break;
1919         }
1920     }
1921     /* Check for timeout. */
1922     if (0U == counter)
1923     {
1924         result = kStatus_Timeout;
1925     }
1926 #else
1927     while (ENET_QOS_IsSMIBusy(base))
1928     {
1929     }
1930 #endif
1931     return result;
1932 }
1933 
1934 /*!
1935  * @brief MDIO write with IEEE802.3 MDIO Clause 22 format.
1936  *
1937  * @param base  ENET peripheral base address.
1938  * @param phyAddr  The PHY address.
1939  * @param regAddr  The PHY register.
1940  * @param data  The data written to PHY.
1941  * @return kStatus_Success  MDIO access succeeds.
1942  * @return kStatus_Timeout  MDIO access timeout.
1943  */
ENET_QOS_MDIOWrite(ENET_QOS_Type * base,uint8_t phyAddr,uint8_t regAddr,uint16_t data)1944 status_t ENET_QOS_MDIOWrite(ENET_QOS_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t data)
1945 {
1946     ENET_QOS_StartSMIWrite(base, phyAddr, regAddr, data);
1947 
1948     return ENET_QOS_MDIOWaitTransferOver(base);
1949 }
1950 
1951 /*!
1952  * @brief MDIO read with IEEE802.3 MDIO Clause 22 format.
1953  *
1954  * @param base  ENET peripheral base address.
1955  * @param phyAddr  The PHY address.
1956  * @param regAddr  The PHY register.
1957  * @param pData  The data read from PHY.
1958  * @return kStatus_Success  MDIO access succeeds.
1959  * @return kStatus_Timeout  MDIO access timeout.
1960  */
ENET_QOS_MDIORead(ENET_QOS_Type * base,uint8_t phyAddr,uint8_t regAddr,uint16_t * pData)1961 status_t ENET_QOS_MDIORead(ENET_QOS_Type *base, uint8_t phyAddr, uint8_t regAddr, uint16_t *pData)
1962 {
1963     assert(pData);
1964 
1965     status_t result;
1966 
1967     ENET_QOS_StartSMIRead(base, phyAddr, regAddr);
1968 
1969     result = ENET_QOS_MDIOWaitTransferOver(base);
1970     if (result != kStatus_Success)
1971     {
1972         return result;
1973     }
1974     *pData = ENET_QOS_ReadSMIData(base);
1975 
1976     return result;
1977 }
1978 
1979 /*!
1980  * @brief MDIO write with IEEE802.3 Clause 45 format.
1981  *
1982  * @param base  ENET peripheral base address.
1983  * @param portAddr  The MDIO port address(PHY address).
1984  * @param devAddr  The device address.
1985  * @param regAddr  The PHY register address.
1986  * @param data  The data written to PHY.
1987  * @return kStatus_Success  MDIO access succeeds.
1988  * @return kStatus_Timeout  MDIO access timeout.
1989  */
ENET_QOS_MDIOC45Write(ENET_QOS_Type * base,uint8_t portAddr,uint8_t devAddr,uint16_t regAddr,uint16_t data)1990 status_t ENET_QOS_MDIOC45Write(ENET_QOS_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t data)
1991 {
1992     ENET_QOS_StartExtC45SMIWrite(base, portAddr, devAddr, regAddr, data);
1993 
1994     return ENET_QOS_MDIOWaitTransferOver(base);
1995 }
1996 
1997 /*!
1998  * @brief MDIO read with IEEE802.3 Clause 45 format.
1999  *
2000  * @param base  ENET peripheral base address.
2001  * @param portAddr  The MDIO port address(PHY address).
2002  * @param devAddr  The device address.
2003  * @param regAddr  The PHY register address.
2004  * @param pData  The data read from PHY.
2005  * @return kStatus_Success  MDIO access succeeds.
2006  * @return kStatus_Timeout  MDIO access timeout.
2007  */
ENET_QOS_MDIOC45Read(ENET_QOS_Type * base,uint8_t portAddr,uint8_t devAddr,uint16_t regAddr,uint16_t * pData)2008 status_t ENET_QOS_MDIOC45Read(ENET_QOS_Type *base, uint8_t portAddr, uint8_t devAddr, uint16_t regAddr, uint16_t *pData)
2009 {
2010     status_t result = kStatus_Success;
2011 
2012     ENET_QOS_StartExtC45SMIRead(base, portAddr, devAddr, regAddr);
2013 
2014     result = ENET_QOS_MDIOWaitTransferOver(base);
2015     if (result != kStatus_Success)
2016     {
2017         return result;
2018     }
2019     *pData = ENET_QOS_ReadSMIData(base);
2020 
2021     return result;
2022 }
2023 
2024 /*!
2025  * brief Set the MAC to enter into power down mode.
2026  * the remote power wake up frame and magic frame can wake up
2027  * the ENET from the power down mode.
2028  *
2029  * param base    ENET peripheral base address.
2030  * param wakeFilter  The wakeFilter provided to configure the wake up frame fitlter.
2031  *  Set the wakeFilter to NULL is not required. But if you have the filter requirement,
2032  *  please make sure the wakeFilter pointer shall be eight continous
2033  *  32-bits configuration.
2034  */
ENET_QOS_EnterPowerDown(ENET_QOS_Type * base,uint32_t * wakeFilter)2035 void ENET_QOS_EnterPowerDown(ENET_QOS_Type *base, uint32_t *wakeFilter)
2036 {
2037     uint8_t index;
2038     uint32_t *reg = wakeFilter;
2039 
2040     /* Disable the tx dma. */
2041     base->DMA_CH[0].DMA_CHX_TX_CTRL &= ~ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK;
2042     base->DMA_CH[1].DMA_CHX_TX_CTRL &= ~ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK;
2043 
2044     /* Disable the mac tx/rx. */
2045     base->MAC_CONFIGURATION &= ~(ENET_QOS_MAC_CONFIGURATION_RE_MASK | ENET_QOS_MAC_CONFIGURATION_TE_MASK);
2046     /* Enable the remote wakeup packet and enable the power down mode. */
2047     if (wakeFilter != NULL)
2048     {
2049         for (index = 0; index < ENET_QOS_WAKEUPFILTER_NUM; index++)
2050         {
2051             base->MAC_RWK_PACKET_FILTER = *reg;
2052             reg++;
2053         }
2054     }
2055     base->MAC_PMT_CONTROL_STATUS = ENET_QOS_MAC_PMT_CONTROL_STATUS_MGKPKTEN_MASK |
2056                                    ENET_QOS_MAC_PMT_CONTROL_STATUS_RWKPKTEN_MASK |
2057                                    ENET_QOS_MAC_PMT_CONTROL_STATUS_PWRDWN_MASK;
2058 
2059     /* Enable the MAC rx. */
2060     base->MAC_CONFIGURATION |= ENET_QOS_MAC_CONFIGURATION_RE_MASK;
2061 }
2062 
2063 /*!
2064  * brief Enable/Disable Rx parser, please notice that for enable/disable Rx Parser,
2065  * should better disable Receive first.
2066  *
2067  * param base    ENET_QOS peripheral base address.
2068  * param enable    Enable/Disable Rx parser function
2069  */
ENET_QOS_EnableRxParser(ENET_QOS_Type * base,bool enable)2070 status_t ENET_QOS_EnableRxParser(ENET_QOS_Type *base, bool enable)
2071 {
2072     status_t result = kStatus_Success;
2073 
2074     if (enable)
2075     {
2076         base->MTL_OPERATION_MODE |= ENET_QOS_MTL_OPERATION_MODE_FRPE_MASK;
2077     }
2078     else
2079     {
2080         base->MTL_OPERATION_MODE &= ~ENET_QOS_MTL_OPERATION_MODE_FRPE_MASK;
2081         result = ENET_QOS_PollStatusFlag(&(base->MTL_RXP_CONTROL_STATUS), ENET_QOS_MTL_RXP_CONTROL_STATUS_RXPI_MASK,
2082                                          ENET_QOS_MTL_RXP_CONTROL_STATUS_RXPI_MASK);
2083     }
2084 
2085     return result;
2086 }
2087 
2088 /*!
2089  * brief Gets the size of the read frame.
2090  * This function gets a received frame size from the ENET buffer descriptors.
2091  * note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS.
2092  * After calling ENET_QOS_GetRxFrameSize, ENET_QOS_ReadFrame() should be called to update the
2093  * receive buffers If the result is not "kStatus_ENET_QOS_RxFrameEmpty".
2094  *
2095  * param handle The ENET handler structure. This is the same handler pointer used in the ENET_QOS_Init.
2096  * param length The length of the valid frame received.
2097  * param channel The DMAC channel for the rx.
2098  * retval kStatus_ENET_QOS_RxFrameEmpty No frame received. Should not call ENET_QOS_ReadFrame to read frame.
2099  * retval kStatus_ENET_QOS_RxFrameError Data error happens. ENET_QOS_ReadFrame should be called with NULL data
2100  *         and NULL length to update the receive buffers.
2101  * retval kStatus_Success Receive a frame Successfully then the ENET_QOS_ReadFrame
2102  *         should be called with the right data buffer and the captured data length input.
2103  */
ENET_QOS_GetRxFrameSize(ENET_QOS_Type * base,enet_qos_handle_t * handle,uint32_t * length,uint8_t channel)2104 status_t ENET_QOS_GetRxFrameSize(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint32_t *length, uint8_t channel)
2105 {
2106     assert(handle != NULL);
2107     assert(length != NULL);
2108 
2109     enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel];
2110     enet_qos_rx_bd_struct_t *rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
2111     uint16_t index                  = rxBdRing->rxGenIdx;
2112     uint32_t control                = rxDesc->control;
2113 
2114     /* Reset the length to zero. */
2115     *length = 0;
2116 
2117     if ((control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U)
2118     {
2119         return kStatus_ENET_QOS_RxFrameEmpty;
2120     }
2121     else
2122     {
2123         do
2124         {
2125             /* Application owns the buffer descriptor, get the length. */
2126             if ((control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U)
2127             {
2128                 if ((control & ENET_QOS_RXDESCRIP_WR_ERRSUM_MASK) != 0U)
2129                 {
2130                     return kStatus_ENET_QOS_RxFrameError;
2131                 }
2132                 *length = (control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK) - ENET_QOS_FCS_LEN;
2133                 return kStatus_Success;
2134             }
2135 
2136             index   = ENET_QOS_IncreaseIndex(index, rxBdRing->rxRingLen);
2137             rxDesc  = &rxBdRing->rxBdBase[index];
2138             control = rxDesc->control;
2139         } while (index != rxBdRing->rxGenIdx);
2140 
2141         return kStatus_ENET_QOS_RxFrameError;
2142     }
2143 }
2144 
ENET_QOS_DropFrame(ENET_QOS_Type * base,enet_qos_handle_t * handle,uint8_t channel)2145 static void ENET_QOS_DropFrame(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint8_t channel)
2146 {
2147     enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel];
2148     enet_qos_rx_bd_struct_t *rxDesc;
2149     uint16_t index      = rxBdRing->rxGenIdx;
2150     bool tsAvailable    = false;
2151     uintptr_t buff1Addr = 0;
2152     uintptr_t buff2Addr = 0;
2153     uint32_t rxDescTail;
2154     uint32_t rdesc1;
2155     uint32_t rdesc3;
2156 
2157     /* Not check DMA ownership here, assume there's at least one valid frame left in BD ring */
2158     do
2159     {
2160         /* Get the control flag. */
2161         rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
2162         rdesc1 = rxDesc->reserved;
2163         rdesc3 = rxDesc->control;
2164 
2165         if (!handle->doubleBuffEnable)
2166         {
2167             buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx];
2168             ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable,
2169                                         handle->doubleBuffEnable);
2170         }
2171         else
2172         {
2173             buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx];
2174             buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
2175             ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
2176                                         handle->rxintEnable, handle->doubleBuffEnable);
2177         }
2178 
2179         rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
2180 
2181         /* Find the last buffer descriptor for the frame. */
2182         if ((rdesc3 & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U)
2183         {
2184             if ((rdesc3 & ENET_QOS_RXDESCRIP_WR_RS1V_MASK) != 0U)
2185             {
2186                 if ((rdesc1 & ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK) != 0U)
2187                 {
2188                     tsAvailable = true;
2189                 }
2190             }
2191 
2192             /* Reinit for the context descriptor which has been updated by DMA. */
2193             rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
2194 
2195             if (tsAvailable && ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) != 0U))
2196             {
2197                 if (!handle->doubleBuffEnable)
2198                 {
2199                     buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx];
2200                     ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable,
2201                                                 handle->doubleBuffEnable);
2202                 }
2203                 else
2204                 {
2205                     buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx];
2206                     buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
2207                     ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
2208                                                 handle->rxintEnable, handle->doubleBuffEnable);
2209                 }
2210                 rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
2211             }
2212             break;
2213         }
2214     } while (rxBdRing->rxGenIdx != index);
2215 
2216     /* Always try to start receive, in case it had stopped */
2217     rxDescTail = (uint32_t)(uintptr_t)&rxBdRing->rxBdBase[rxBdRing->rxRingLen];
2218 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2219     rxDescTail = MEMORY_ConvertMemoryMapAddress(rxDescTail, kMEMORY_Local2DMA);
2220 #endif
2221     base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = rxDescTail;
2222     base->DMA_CH[channel].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;
2223 }
2224 
2225 /*!
2226  * brief Reads a frame from the ENET device.
2227  * This function reads a frame from the ENET DMA descriptors.
2228  * The ENET_QOS_GetRxFrameSize should be used to get the size of the prepared data buffer.
2229  * For example use rx dma channel 0:
2230  * code
2231  *       uint32_t length;
2232  *       enet_qos_handle_t g_handle;
2233  *       enet_qos_ptp_time_t ts;
2234  *       status = ENET_QOS_GetRxFrameSize(&g_handle, &length, 0);
2235  *       if (length != 0)
2236  *       {
2237  *           uint8_t *data = memory allocate interface;
2238  *           if (!data)
2239  *           {
2240  *               ENET_QOS_ReadFrame(ENET, &g_handle, NULL, 0, 0, &ts);
2241  *           }
2242  *           else
2243  *           {
2244  *              status = ENET_QOS_ReadFrame(ENET, &g_handle, data, length, 0, &ts);
2245  *           }
2246  *       }
2247  *       else if (status == kStatus_ENET_QOS_RxFrameError)
2248  *       {
2249  *           ENET_QOS_ReadFrame(ENET, &g_handle, NULL, 0, 0, &ts);
2250  *       }
2251  * endcode
2252  * param base  ENET peripheral base address.
2253  * param handle The ENET handler structure. This is the same handler pointer used in the ENET_QOS_Init.
2254  * param data The data buffer provided by user to store the frame which memory size should be at least "length".
2255  * param length The size of the data buffer which is still the length of the received frame.
2256  * param channel The rx DMA channel. shall not be larger than 2.
2257  * return The execute status, successful or failure.
2258  */
ENET_QOS_ReadFrame(ENET_QOS_Type * base,enet_qos_handle_t * handle,uint8_t * data,uint32_t length,uint8_t channel,enet_qos_ptp_time_t * ts)2259 status_t ENET_QOS_ReadFrame(ENET_QOS_Type *base,
2260                             enet_qos_handle_t *handle,
2261                             uint8_t *data,
2262                             uint32_t length,
2263                             uint8_t channel,
2264                             enet_qos_ptp_time_t *ts)
2265 {
2266     assert(handle != NULL);
2267     assert(channel < handle->rxQueueUse);
2268 
2269     uint32_t len    = 0;
2270     uint32_t offset = 0;
2271     uint32_t control;
2272     bool isLastBuff                 = false;
2273     enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel];
2274     enet_qos_rx_bd_struct_t *rxDesc;
2275     status_t result     = kStatus_Fail;
2276     uintptr_t buff1Addr = 0; /*!< Buffer 1 address */
2277     uintptr_t buff2Addr = 0; /*!< Buffer 2 or next descriptor address */
2278     uint32_t rxDescTail;
2279 
2280     bool tsAvailable = false;
2281 
2282     /* For data-NULL input, only update the buffer descriptor. */
2283     if (data == NULL)
2284     {
2285         ENET_QOS_DropFrame(base, handle, channel);
2286         result = kStatus_Success;
2287     }
2288     else
2289     {
2290         while (!isLastBuff)
2291         {
2292             /* The last buffer descriptor of a frame. */
2293             rxDesc  = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
2294             control = rxDesc->control;
2295 
2296             if (!handle->doubleBuffEnable)
2297             {
2298                 buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx];
2299                 if (handle->rxMaintainEnable[channel])
2300                 {
2301 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2302                     /* Add the cache invalidate maintain. */
2303                     ENET_QOS_DcacheInvalidateByRange(MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local),
2304                                                      rxBdRing->rxBuffSizeAlign);
2305 #else
2306                     /* Add the cache invalidate maintain. */
2307                     ENET_QOS_DcacheInvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign);
2308 #endif
2309                 }
2310             }
2311             else
2312             {
2313                 buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx];
2314                 buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
2315                 if (handle->rxMaintainEnable[channel])
2316                 {
2317 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2318                     /* Add the cache invalidate maintain. */
2319                     ENET_QOS_DcacheInvalidateByRange(MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local),
2320                                                      rxBdRing->rxBuffSizeAlign);
2321                     /* Add the cache invalidate maintain. */
2322                     ENET_QOS_DcacheInvalidateByRange(MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local),
2323                                                      rxBdRing->rxBuffSizeAlign);
2324 #else
2325                     /* Add the cache invalidate maintain. */
2326                     ENET_QOS_DcacheInvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign);
2327                     /* Add the cache invalidate maintain. */
2328                     ENET_QOS_DcacheInvalidateByRange(buff2Addr, rxBdRing->rxBuffSizeAlign);
2329 #endif
2330                 }
2331             }
2332 
2333             rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
2334 
2335             if ((control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U)
2336             {
2337                 /* This is a valid frame. */
2338                 isLastBuff = true;
2339 
2340                 /* Remove FCS */
2341                 len = (control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK) - ENET_QOS_FCS_LEN;
2342 
2343                 if (length == len)
2344                 {
2345                     /* Copy the frame to user's buffer. */
2346                     len -= offset;
2347 
2348                     if (len > rxBdRing->rxBuffSizeAlign)
2349                     {
2350 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2351                         (void)memcpy((void *)&data[offset],
2352                                      (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local),
2353                                      rxBdRing->rxBuffSizeAlign);
2354 #else
2355                         (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff1Addr, rxBdRing->rxBuffSizeAlign);
2356 #endif
2357                         offset += rxBdRing->rxBuffSizeAlign;
2358 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2359                         (void)memcpy((void *)&data[offset],
2360                                      (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local),
2361                                      len - rxBdRing->rxBuffSizeAlign);
2362 #else
2363                         (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff2Addr,
2364                                      len - rxBdRing->rxBuffSizeAlign);
2365 #endif
2366                     }
2367                     else
2368                     {
2369 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2370                         (void)memcpy((void *)&data[offset],
2371                                      (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local),
2372                                      len);
2373 #else
2374                         (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff1Addr, len);
2375 #endif
2376                     }
2377 
2378                     result = kStatus_Success;
2379                 }
2380 
2381                 if ((rxDesc->reserved & ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK) != 0U)
2382                 {
2383                     tsAvailable = true;
2384                 }
2385                 /* Updates the receive buffer descriptors. */
2386                 ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
2387                                             handle->rxintEnable, handle->doubleBuffEnable);
2388                 /* Store the rx timestamp which is in the next buffer descriptor of the last
2389                  * descriptor of a frame. */
2390                 rxDesc  = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
2391                 control = rxDesc->control;
2392 
2393                 /* If tsAvailable is true, a context descriptor is expected but might not be yet
2394                  * available.
2395                  */
2396                 if (tsAvailable)
2397                 {
2398                     uint8_t retryTimes = 10;
2399 
2400                     while (((control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U) ||
2401                            ((control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) == 0U))
2402                     {
2403                         SDK_DelayAtLeastUs(1U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
2404                         if (0U == retryTimes--)
2405                         {
2406                             assert(false);
2407                         }
2408                         control = rxDesc->control;
2409                     }
2410 
2411                     /* Reinit for the context descriptor which has been updated by DMA. */
2412                     if (NULL != ts)
2413                     {
2414                         ENET_QOS_StoreRxFrameTime(base, handle, rxDesc, ts);
2415                     }
2416 
2417                     if (!handle->doubleBuffEnable)
2418                     {
2419                         buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx];
2420                         ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable,
2421                                                     handle->doubleBuffEnable);
2422                     }
2423                     else
2424                     {
2425                         buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx];
2426                         buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
2427                         ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
2428                                                     handle->rxintEnable, handle->doubleBuffEnable);
2429                     }
2430                     rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
2431                 }
2432             }
2433             else
2434             {
2435                 /* Store a frame on several buffer descriptors. */
2436                 isLastBuff = false;
2437                 /* Length check. */
2438                 if (offset >= length)
2439                 {
2440                     /* Updates the receive buffer descriptors. */
2441                     ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
2442                                                 handle->rxintEnable, handle->doubleBuffEnable);
2443                     break;
2444                 }
2445 
2446 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2447                 (void)memcpy((void *)&data[offset],
2448                              (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local),
2449                              rxBdRing->rxBuffSizeAlign);
2450 #else
2451                 (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff1Addr, rxBdRing->rxBuffSizeAlign);
2452 #endif
2453 
2454                 offset += rxBdRing->rxBuffSizeAlign;
2455                 if (buff2Addr != 0U)
2456                 {
2457 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2458                     (void)memcpy((void *)&data[offset],
2459                                  (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local),
2460                                  rxBdRing->rxBuffSizeAlign);
2461 #else
2462                     (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff2Addr, rxBdRing->rxBuffSizeAlign);
2463 #endif
2464                     offset += rxBdRing->rxBuffSizeAlign;
2465                 }
2466 
2467                 ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
2468                                             handle->rxintEnable, handle->doubleBuffEnable);
2469             }
2470         }
2471 
2472         /* Always try to start receive, in case it had stopped */
2473         rxDescTail = (uint32_t)(uintptr_t)&rxBdRing->rxBdBase[rxBdRing->rxRingLen];
2474 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2475         rxDescTail = MEMORY_ConvertMemoryMapAddress(rxDescTail, kMEMORY_Local2DMA);
2476 #endif
2477         base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = rxDescTail;
2478         base->DMA_CH[channel].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;
2479     }
2480 
2481     return result;
2482 }
2483 
2484 /*!
2485  * brief Updates the buffers and the own status for a given rx descriptor.
2486  *  This function is a low level functional API to Updates the
2487  *  buffers and the own status for a given rx descriptor.
2488  *
2489  * param rxDesc  The given rx descriptor.
2490  * param buffer1  The first buffer address in the descriptor.
2491  * param buffer2  The second buffer address in the descriptor.
2492  * param intEnable Interrupt enable flag.
2493  * param doubleBuffEnable The double buffer enable flag.
2494  *
2495  * note This must be called after all the ENET initilization.
2496  * And should be called when the ENET receive/transmit is required.
2497  */
ENET_QOS_UpdateRxDescriptor(enet_qos_rx_bd_struct_t * rxDesc,void * buffer1,void * buffer2,bool intEnable,bool doubleBuffEnable)2498 void ENET_QOS_UpdateRxDescriptor(
2499     enet_qos_rx_bd_struct_t *rxDesc, void *buffer1, void *buffer2, bool intEnable, bool doubleBuffEnable)
2500 {
2501     assert(rxDesc != NULL);
2502     uint32_t control = ENET_QOS_RXDESCRIP_RD_OWN_MASK | ENET_QOS_RXDESCRIP_RD_BUFF1VALID_MASK;
2503 
2504     if (intEnable)
2505     {
2506         control |= ENET_QOS_RXDESCRIP_RD_IOC_MASK;
2507     }
2508 
2509     if (doubleBuffEnable)
2510     {
2511         control |= ENET_QOS_RXDESCRIP_RD_BUFF2VALID_MASK;
2512     }
2513 
2514     /* Update the buffer if needed. */
2515     if (buffer1 != NULL)
2516     {
2517         rxDesc->buff1Addr = (uint32_t)(uintptr_t)(uint8_t *)buffer1;
2518     }
2519     if (buffer2 != NULL)
2520     {
2521         rxDesc->buff2Addr = (uint32_t)(uintptr_t)(uint8_t *)buffer2;
2522     }
2523     else
2524     {
2525         rxDesc->buff2Addr = 0;
2526     }
2527 
2528     rxDesc->reserved = 0;
2529 
2530     /* Add a data barrier to be sure that the address is written before the
2531       ownership bit status. */
2532     __DMB();
2533 
2534     rxDesc->control = control;
2535 }
2536 
2537 /*!
2538  * brief Setup a given tx descriptor.
2539  *  This function is a low level functional API to setup or prepare
2540  *  a given tx descriptor.
2541  *
2542  * param txDesc  The given tx descriptor.
2543  * param buffer1  The first buffer address in the descriptor.
2544  * param bytes1  The bytes in the fist buffer.
2545  * param buffer2  The second buffer address in the descriptor.
2546  * param bytes1  The bytes in the second buffer.
2547  * param framelen  The length of the frame to be transmitted.
2548  * param intEnable Interrupt enable flag.
2549  * param tsEnable The timestamp enable.
2550  * param flag The flag of this tx desciriptor, see "enet_qos_desc_flag" .
2551  * param slotNum The slot num used for AV  only.
2552  *
2553  * note This must be called after all the ENET initilization.
2554  * And should be called when the ENET receive/transmit is required.
2555  * Transmit buffers are 'zero-copy' buffers, so the buffer must remain in
2556  * memory until the packet has been fully transmitted. The buffers
2557  * should be free or requeued in the transmit interrupt irq handler.
2558  */
ENET_QOS_SetupTxDescriptor(enet_qos_tx_bd_struct_t * txDesc,void * buffer1,uint32_t bytes1,void * buffer2,uint32_t bytes2,uint32_t framelen,bool intEnable,bool tsEnable,enet_qos_desc_flag flag,uint8_t slotNum)2559 void ENET_QOS_SetupTxDescriptor(enet_qos_tx_bd_struct_t *txDesc,
2560                                 void *buffer1,
2561                                 uint32_t bytes1,
2562                                 void *buffer2,
2563                                 uint32_t bytes2,
2564                                 uint32_t framelen,
2565                                 bool intEnable,
2566                                 bool tsEnable,
2567                                 enet_qos_desc_flag flag,
2568                                 uint8_t slotNum)
2569 {
2570     uint32_t control = ENET_QOS_TXDESCRIP_RD_BL1(bytes1) | ENET_QOS_TXDESCRIP_RD_BL2(bytes2);
2571 
2572     if (tsEnable)
2573     {
2574         control |= ENET_QOS_TXDESCRIP_RD_TTSE_MASK;
2575     }
2576     else
2577     {
2578         control &= ~ENET_QOS_TXDESCRIP_RD_TTSE_MASK;
2579     }
2580 
2581     if (intEnable)
2582     {
2583         control |= ENET_QOS_TXDESCRIP_RD_IOC_MASK;
2584     }
2585     else
2586     {
2587         control &= ~ENET_QOS_TXDESCRIP_RD_IOC_MASK;
2588     }
2589 
2590 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2591     buffer1 = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)buffer1, kMEMORY_Local2DMA);
2592     buffer2 = (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)buffer2, kMEMORY_Local2DMA);
2593 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
2594 
2595     /* Preare the descriptor for transmit. */
2596     txDesc->buff1Addr = (uint32_t)(uintptr_t)(uint8_t *)buffer1;
2597     txDesc->buff2Addr = (uint32_t)(uintptr_t)(uint8_t *)buffer2;
2598     txDesc->buffLen   = control;
2599 
2600     /* Make sure all fields of descriptor are written before setting ownership */
2601     __DMB();
2602 
2603     control = ENET_QOS_TXDESCRIP_RD_FL(framelen) | ENET_QOS_TXDESCRIP_RD_LDFD(flag) | ENET_QOS_TXDESCRIP_RD_OWN_MASK;
2604 
2605     txDesc->controlStat = control;
2606 
2607     /* Make sure the descriptor is written in memory (before MAC starts checking it) */
2608     __DSB();
2609 }
2610 
2611 /*!
2612  * brief Configure a given tx descriptor.
2613  *  This function is a low level functional API to setup or prepare
2614  *  a given tx descriptor.
2615  *
2616  * param txDesc  The given tx descriptor.
2617  * param config  The tx descriptor configuration.
2618  *
2619  * note This must be called after all the ENET initilization.
2620  * And should be called when the ENET receive/transmit is required.
2621  * Transmit buffers are 'zero-copy' buffers, so the buffer must remain in
2622  * memory until the packet has been fully transmitted. The buffers
2623  * should be free or requeued in the transmit interrupt irq handler.
2624  */
ENET_QOS_ConfigTxDescriptor(enet_qos_tx_bd_struct_t * txDesc,enet_qos_tx_bd_config_struct_t * config)2625 static void ENET_QOS_ConfigTxDescriptor(enet_qos_tx_bd_struct_t *txDesc, enet_qos_tx_bd_config_struct_t *config)
2626 {
2627     uint32_t control = ENET_QOS_TXDESCRIP_RD_BL1(config->bytes1) | ENET_QOS_TXDESCRIP_RD_BL2(config->bytes2);
2628 
2629     if (config->tsEnable)
2630     {
2631         control |= ENET_QOS_TXDESCRIP_RD_TTSE_MASK;
2632     }
2633     else
2634     {
2635         control &= ~ENET_QOS_TXDESCRIP_RD_TTSE_MASK;
2636     }
2637 
2638     if (config->intEnable)
2639     {
2640         control |= ENET_QOS_TXDESCRIP_RD_IOC_MASK;
2641     }
2642     else
2643     {
2644         control &= ~ENET_QOS_TXDESCRIP_RD_IOC_MASK;
2645     }
2646 
2647     /* Preare the descriptor for transmit. */
2648 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2649     txDesc->buff1Addr = MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)config->buffer1, kMEMORY_Local2DMA);
2650     txDesc->buff2Addr = MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)config->buffer2, kMEMORY_Local2DMA);
2651 #else
2652     txDesc->buff1Addr = (uint32_t)(uintptr_t)(uint8_t *)config->buffer1;
2653     txDesc->buff2Addr = (uint32_t)(uintptr_t)(uint8_t *)config->buffer2;
2654 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
2655     txDesc->buffLen = control;
2656 
2657     /* Make sure all fields of descriptor are written before setting ownership */
2658     __DMB();
2659 
2660     control = ENET_QOS_TXDESCRIP_RD_FL(config->framelen) | ENET_QOS_TXDESCRIP_RD_CIC(config->txOffloadOps) |
2661               ENET_QOS_TXDESCRIP_RD_LDFD(config->flag) | ENET_QOS_TXDESCRIP_RD_OWN_MASK;
2662 
2663     txDesc->controlStat = control;
2664 
2665     /* Make sure the descriptor is written in memory (before MAC starts checking it) */
2666     __DSB();
2667 }
2668 
2669 /*!
2670  * brief Reclaim tx descriptors.
2671  *  This function is used to update the tx descriptor status and
2672  *  store the tx timestamp when the 1588 feature is enabled.
2673  *  This is called by the transmit interupt IRQ handler after the
2674  *  complete of a frame transmission.
2675  *
2676  * param base    ENET peripheral base address.
2677  * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_QOS_Init.
2678  * param channel  The tx DMA channnel.
2679  *
2680  */
ENET_QOS_ReclaimTxDescriptor(ENET_QOS_Type * base,enet_qos_handle_t * handle,uint8_t channel)2681 void ENET_QOS_ReclaimTxDescriptor(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint8_t channel)
2682 {
2683     enet_qos_tx_bd_ring_t *txBdRing       = &handle->txBdRing[channel];
2684     enet_qos_tx_bd_struct_t *txDesc       = &txBdRing->txBdBase[txBdRing->txConsumIdx];
2685     enet_qos_tx_dirty_ring_t *txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[channel];
2686     enet_qos_frame_info_t *txDirty        = NULL;
2687     uint32_t control, primask;
2688 
2689     control = txDesc->controlStat;
2690 
2691     /* Need to update the first index for transmit buffer free. */
2692     while ((txBdRing->txDescUsed > 0U) && (0U == (control & ENET_QOS_TXDESCRIP_RD_OWN_MASK)))
2693     {
2694         if ((control & ENET_QOS_TXDESCRIP_RD_LD_MASK) != 0U)
2695         {
2696             if (ENET_QOS_TxDirtyRingAvailable(txDirtyRing))
2697             {
2698                 txDirty               = &txDirtyRing->txDirtyBase[txBdRing->txConsumIdx];
2699                 txDirtyRing->txGenIdx = ENET_QOS_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen);
2700                 if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx)
2701                 {
2702                     txDirtyRing->isFull = true;
2703                 }
2704 
2705                 if ((control & ENET_QOS_TXDESCRIP_WB_TTSS_MASK) != 0U)
2706                 {
2707                     enet_qos_ptp_time_t *ts = &txDirty->timeStamp;
2708                     uint32_t nanosecond;
2709                     /* Get transmit time stamp second. */
2710                     nanosecond         = txDesc->buff1Addr;
2711                     txDirty->isTsAvail = true;
2712                     if (0U == (base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK))
2713                     {
2714                         /* Binary rollover, 0.465ns accuracy. */
2715                         nanosecond = (nanosecond * 465U) / 1000U;
2716                     }
2717                     ts->second     = txDesc->buff2Addr;
2718                     ts->nanosecond = nanosecond;
2719                 }
2720                 else
2721                 {
2722                     txDirty->isTsAvail = false;
2723                 }
2724             }
2725         }
2726 
2727         /* For tx buffer free or requeue for each descriptor.
2728          * The tx interrupt callback should free/requeue the tx buffer. */
2729         if (handle->callback != NULL)
2730         {
2731             handle->callback(base, handle, kENET_QOS_TxIntEvent, channel, handle->userData);
2732         }
2733 
2734         primask = DisableGlobalIRQ();
2735         txBdRing->txDescUsed--;
2736         EnableGlobalIRQ(primask);
2737 
2738         /* Update the txConsumIdx/txDesc. */
2739         txBdRing->txConsumIdx = ENET_QOS_IncreaseIndex(txBdRing->txConsumIdx, txBdRing->txRingLen);
2740         txDesc                = &txBdRing->txBdBase[txBdRing->txConsumIdx];
2741         control               = txDesc->controlStat;
2742     }
2743 }
2744 
2745 /*!
2746  * brief Transmits an ENET frame.
2747  * note The CRC is automatically appended to the data. Input the data
2748  * to send without the CRC.
2749  *
2750  * param base  ENET peripheral base address.
2751  * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_QOS_Init.
2752  * param data The data buffer provided by user to be send.
2753  * param length The length of the data to be send.
2754  * param channel Channel to send the frame, same with queue index.
2755  * param isNeedTs True means save timestamp
2756  * param context pointer to user context to be kept in the tx dirty frame information.
2757  * param txOffloadOps The Tx frame checksum offload option.
2758  * retval kStatus_Success  Send frame succeed.
2759  * retval kStatus_ENET_QOS_TxFrameBusy  Transmit buffer descriptor is busy under transmission.
2760  *         The transmit busy happens when the data send rate is over the MAC capacity.
2761  *         The waiting mechanism is recommended to be added after each call return with
2762  *         kStatus_ENET_QOS_TxFrameBusy.
2763  */
ENET_QOS_SendFrame(ENET_QOS_Type * base,enet_qos_handle_t * handle,uint8_t * data,uint32_t length,uint8_t channel,bool isNeedTs,void * context,enet_qos_tx_offload_t txOffloadOps)2764 status_t ENET_QOS_SendFrame(ENET_QOS_Type *base,
2765                             enet_qos_handle_t *handle,
2766                             uint8_t *data,
2767                             uint32_t length,
2768                             uint8_t channel,
2769                             bool isNeedTs,
2770                             void *context,
2771                             enet_qos_tx_offload_t txOffloadOps)
2772 {
2773     assert(handle != NULL);
2774     assert(data != NULL);
2775     assert(channel < handle->txQueueUse);
2776 
2777     enet_qos_tx_bd_config_struct_t txDescConfig;
2778     enet_qos_tx_bd_ring_t *txBdRing;
2779     enet_qos_tx_bd_struct_t *txDesc;
2780     enet_qos_tx_dirty_ring_t *txDirtyRing;
2781     enet_qos_frame_info_t *txDirty;
2782     uint32_t primask;
2783     uint32_t txDescTail;
2784 
2785 #if (!defined(FSL_FEATURE_ENET_QOS_TX_OFFLOAD_QUEUE_SUPPORT_BITMAP)) || \
2786     (FSL_FEATURE_ENET_QOS_TX_OFFLOAD_QUEUE_SUPPORT_BITMAP == 0)
2787     assert(txOffloadOps == kENET_QOS_TxOffloadDisable);
2788 #else
2789     assert((txOffloadOps == kENET_QOS_TxOffloadDisable) ||
2790            (((uint32_t)FSL_FEATURE_ENET_QOS_TX_OFFLOAD_QUEUE_SUPPORT_BITMAP & ((uint32_t)1U << channel)) != 0U));
2791 #endif /* FSL_FEATURE_ENET_QOS_TX_OFFLOAD_QUEUE_SUPPORT_BITMAP == 0 */
2792 
2793     if (length > 2U * ENET_QOS_TXDESCRIP_RD_BL1_MASK)
2794     {
2795         return kStatus_ENET_QOS_TxFrameOverLen;
2796     }
2797 
2798     /* Check if the DMA owns the descriptor. */
2799     txBdRing = (enet_qos_tx_bd_ring_t *)&handle->txBdRing[channel];
2800     txDesc   = &txBdRing->txBdBase[txBdRing->txGenIdx];
2801     if (txBdRing->txRingLen == txBdRing->txDescUsed)
2802     {
2803         return kStatus_ENET_QOS_TxFrameBusy;
2804     }
2805 
2806     txDirtyRing      = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[channel];
2807     txDirty          = &txDirtyRing->txDirtyBase[txBdRing->txGenIdx];
2808     txDirty->context = context;
2809 
2810     /* Fill the descriptor. */
2811     txDescConfig.framelen     = length;
2812     txDescConfig.flag         = kENET_QOS_FirstLastFlag;
2813     txDescConfig.intEnable    = true;
2814     txDescConfig.tsEnable     = isNeedTs;
2815     txDescConfig.txOffloadOps = txOffloadOps;
2816 
2817     if (length <= ENET_QOS_TXDESCRIP_RD_BL1_MASK)
2818     {
2819         txDescConfig.buffer1 = data;
2820         txDescConfig.bytes1  = length;
2821         txDescConfig.buffer2 = NULL;
2822         txDescConfig.bytes2  = 0;
2823     }
2824     else
2825     {
2826         txDescConfig.buffer1 = data;
2827         txDescConfig.bytes1  = ENET_QOS_TXDESCRIP_RD_BL1_MASK;
2828         txDescConfig.buffer2 = &data[ENET_QOS_TXDESCRIP_RD_BL1_MASK];
2829         txDescConfig.bytes2  = length - ENET_QOS_TXDESCRIP_RD_BL1_MASK;
2830     }
2831     ENET_QOS_ConfigTxDescriptor(txDesc, &txDescConfig);
2832 
2833     /* Increase the index. */
2834     txBdRing->txGenIdx = ENET_QOS_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen);
2835     /* Disable interrupt first and then enable interrupt to avoid the race condition. */
2836     primask = DisableGlobalIRQ();
2837     txBdRing->txDescUsed++;
2838     EnableGlobalIRQ(primask);
2839 
2840     /* Update the transmit tail address. */
2841     txDesc = &txBdRing->txBdBase[txBdRing->txGenIdx];
2842     if (txBdRing->txGenIdx == 0U)
2843     {
2844         txDesc = &txBdRing->txBdBase[txBdRing->txRingLen];
2845     }
2846     txDescTail = (uint32_t)(uintptr_t)txDesc & ~ENET_QOS_ADDR_ALIGNMENT;
2847 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
2848     txDescTail = MEMORY_ConvertMemoryMapAddress(txDescTail, kMEMORY_Local2DMA);
2849 #endif
2850     base->DMA_CH[channel].DMA_CHX_TXDESC_TAIL_PTR = txDescTail;
2851 
2852     return kStatus_Success;
2853 }
2854 
2855 /*!
2856  * brief Gets the sent frame.
2857  *
2858  * This function is used to get the sent frame for timestamp and buffer clean operation.
2859  *
2860  * param handle The ENET handler pointer.This is the same state pointer used in
2861  *        ENET_QOS_Init.
2862  * param txFrame Input parameter, pointer to enet_qos_frame_info_t for saving read out frame information.
2863  * param channel Read out frame from specified channel.
2864  */
ENET_QOS_GetTxFrame(enet_qos_handle_t * handle,enet_qos_frame_info_t * txFrame,uint8_t channel)2865 void ENET_QOS_GetTxFrame(enet_qos_handle_t *handle, enet_qos_frame_info_t *txFrame, uint8_t channel)
2866 {
2867     assert(handle != NULL);
2868     assert(channel < handle->txQueueUse);
2869 
2870     enet_qos_tx_dirty_ring_t *txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[channel];
2871     enet_qos_frame_info_t *txDirty        = &txDirtyRing->txDirtyBase[txDirtyRing->txConsumIdx];
2872 
2873     (void)memcpy(txFrame, txDirty, sizeof(enet_qos_frame_info_t));
2874 
2875     txDirtyRing->isFull      = false;
2876     txDirtyRing->txConsumIdx = ENET_QOS_IncreaseIndex(txDirtyRing->txConsumIdx, txDirtyRing->txRingLen);
2877 }
2878 
ENET_QOS_GetRxFrameErr(enet_qos_rx_bd_struct_t * rxDesc,enet_qos_rx_frame_error_t * rxFrameError)2879 static inline void ENET_QOS_GetRxFrameErr(enet_qos_rx_bd_struct_t *rxDesc, enet_qos_rx_frame_error_t *rxFrameError)
2880 {
2881     uint32_t rdes2 = rxDesc->buff2Addr;
2882     uint32_t rdes3 = rxDesc->control;
2883 
2884     (void)memset(rxFrameError, 0, sizeof(enet_qos_rx_frame_error_t));
2885 
2886     if ((rdes2 & ENET_QOS_RXDESCRIP_WR_SA_FAILURE_MASK) != 0U)
2887     {
2888         rxFrameError->rxSrcAddrFilterErr = true;
2889     }
2890     if ((rdes2 & ENET_QOS_RXDESCRIP_WR_DA_FAILURE_MASK) != 0U)
2891     {
2892         rxFrameError->rxDstAddrFilterErr = true;
2893     }
2894     if ((rdes3 & ENET_QOS_RXDESCRIP_WR_DE_MASK) != 0U)
2895     {
2896         rxFrameError->rxDstAddrFilterErr = true;
2897     }
2898     if ((rdes3 & ENET_QOS_RXDESCRIP_WR_RE_MASK) != 0U)
2899     {
2900         rxFrameError->rxReceiveErr = true;
2901     }
2902     if ((rdes3 & ENET_QOS_RXDESCRIP_WR_OE_MASK) != 0U)
2903     {
2904         rxFrameError->rxOverFlowErr = true;
2905     }
2906     if ((rdes3 & ENET_QOS_RXDESCRIP_WR_RWT_MASK) != 0U)
2907     {
2908         rxFrameError->rxWatchDogErr = true;
2909     }
2910     if ((rdes3 & ENET_QOS_RXDESCRIP_WR_GP_MASK) != 0U)
2911     {
2912         rxFrameError->rxGaintPacketErr = true;
2913     }
2914     if ((rdes3 & ENET_QOS_RXDESCRIP_WR_CRC_MASK) != 0U)
2915     {
2916         rxFrameError->rxCrcErr = true;
2917     }
2918 }
2919 
2920 /*!
2921  * brief Receives one frame in specified BD ring with zero copy.
2922  *
2923  * This function will use the user-defined allocate and free callback. Every time application gets one frame through
2924  * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application.
2925  * note This function will drop current frame and update related BDs as available for DMA if new buffers allocating
2926  * fails. Application must provide a memory pool including at least BD number + 1 buffers(+2 if enable double buffer)
2927  * to make this function work normally. If user calls this function in Rx interrupt handler, be careful that this
2928  * function makes Rx BD ready with allocating new buffer(normal) or updating current BD(out of memory). If there's
2929  * always new Rx frame input, Rx interrupt will be triggered forever. Application need to disable Rx interrupt according
2930  * to specific design in this case.
2931  *
2932  * param base   ENET peripheral base address.
2933  * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init.
2934  * param rxFrame The received frame information structure provided by user.
2935  * param ringId The ring index or ring number.
2936  * retval kStatus_Success  Succeed to get one frame and allocate new memory for Rx buffer.
2937  * retval kStatus_ENET_QOS_RxFrameEmpty  There's no Rx frame in the BD.
2938  * retval kStatus_ENET_QOS_RxFrameError  There's issue in this receiving.
2939  * retval kStatus_ENET_QOS_RxFrameDrop  There's no new buffer memory for BD, drop this frame.
2940  */
ENET_QOS_GetRxFrame(ENET_QOS_Type * base,enet_qos_handle_t * handle,enet_qos_rx_frame_struct_t * rxFrame,uint8_t channel)2941 status_t ENET_QOS_GetRxFrame(ENET_QOS_Type *base,
2942                              enet_qos_handle_t *handle,
2943                              enet_qos_rx_frame_struct_t *rxFrame,
2944                              uint8_t channel)
2945 {
2946     assert(handle != NULL);
2947     assert(channel < handle->rxQueueUse);
2948 
2949     enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel];
2950     enet_qos_rx_bd_struct_t *rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
2951     uint16_t index                  = rxBdRing->rxGenIdx;
2952     status_t result                 = kStatus_Success;
2953     uintptr_t buff1Addr             = 0;
2954     uintptr_t buff2Addr             = 0;
2955     uint16_t buff1Len               = 0;
2956     uint16_t buff2Len               = 0;
2957     uint16_t offset                 = 0;
2958     void *newBuff1                  = NULL;
2959     void *newBuff2                  = NULL;
2960     bool isDrop                     = false;
2961     bool isLastBuff                 = false;
2962     bool tsAvailable                = false;
2963     uint32_t rxDescTail;
2964 
2965     /* Check the frame status. */
2966     do
2967     {
2968         if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U)
2969         {
2970             /* There is at least one buffer owned by DMA. Make sure reception is enabled. */
2971             base->DMA_CH[channel].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;
2972 
2973             result = kStatus_ENET_QOS_RxFrameEmpty;
2974             break;
2975         }
2976 
2977         /* Check timestamp and error. */
2978         if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U)
2979         {
2980             if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_RS1V_MASK) != 0U)
2981             {
2982                 if ((rxDesc->reserved & ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK) != 0U)
2983                 {
2984                     /* Context descriptor is expected but might not be yet available. */
2985                     uint8_t retryTimes = 10;
2986 
2987                     while (((rxDesc->control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U) ||
2988                            ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) == 0U))
2989                     {
2990                         /* Timsstamp value is not corrupted. */
2991                         if ((rxDesc->buff1Addr != 0xFFFFFFFFU) && (rxDesc->buff2Addr != 0xFFFFFFFFU))
2992                         {
2993                             break;
2994                         }
2995                         if (retryTimes-- == 0U)
2996                         {
2997                             break;
2998                         }
2999                     }
3000 
3001                     if (retryTimes != 0U)
3002                     {
3003                         tsAvailable = true;
3004                     }
3005                     else
3006                     {
3007                         result = kStatus_ENET_QOS_RxFrameEmpty;
3008                         break;
3009                     }
3010                 }
3011             }
3012 
3013             /* Get the frame error if there is. */
3014             if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_ERRSUM_MASK) != 0U)
3015             {
3016                 ENET_QOS_GetRxFrameErr(rxDesc, &rxFrame->rxFrameError);
3017                 result = kStatus_ENET_QOS_RxFrameError;
3018             }
3019             else if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK) == 0U)
3020             {
3021                 result = kStatus_ENET_QOS_RxFrameEmpty;
3022             }
3023             else
3024             {
3025                 /* Intentional empty */
3026             }
3027             break;
3028         }
3029 
3030         index = ENET_QOS_IncreaseIndex(index, rxBdRing->rxRingLen);
3031         if (index == rxBdRing->rxGenIdx)
3032         {
3033             result = kStatus_ENET_QOS_RxFrameEmpty;
3034             break;
3035         }
3036         rxDesc = &rxBdRing->rxBdBase[index];
3037     } while (index != rxBdRing->rxGenIdx);
3038 
3039     /* Drop the error frame and return error. */
3040     if (result != kStatus_Success)
3041     {
3042         if (result == kStatus_ENET_QOS_RxFrameError)
3043         {
3044             ENET_QOS_DropFrame(base, handle, channel);
3045         }
3046         return result;
3047     }
3048 
3049     /* Get the valid frame */
3050     index = 0;
3051     do
3052     {
3053         rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
3054 
3055         /* Caculate the buffer and frame length. */
3056         if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U)
3057         {
3058             isLastBuff      = true;
3059             rxFrame->totLen = (uint16_t)(rxDesc->control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK);
3060 
3061             if (rxFrame->totLen - offset > (uint16_t)rxBdRing->rxBuffSizeAlign)
3062             {
3063                 buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
3064                 if (handle->doubleBuffEnable)
3065                 {
3066                     buff2Len = rxFrame->totLen - offset - (uint16_t)rxBdRing->rxBuffSizeAlign - ENET_QOS_FCS_LEN;
3067                 }
3068             }
3069             else
3070             {
3071                 buff1Len = rxFrame->totLen - offset - ENET_QOS_FCS_LEN;
3072             }
3073             rxFrame->totLen -= ENET_QOS_FCS_LEN;
3074         }
3075         else
3076         {
3077             if (!handle->doubleBuffEnable)
3078             {
3079                 buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
3080                 offset += buff1Len;
3081             }
3082             else
3083             {
3084                 buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
3085                 buff2Len = (uint16_t)rxBdRing->rxBuffSizeAlign;
3086                 offset += buff1Len + buff2Len;
3087             }
3088         }
3089 
3090         /* Allocate new buffer to replace the buffer taken by application */
3091         newBuff1 = handle->rxBuffAlloc(base, handle->userData, channel);
3092         if (newBuff1 == NULL)
3093         {
3094             isDrop = true;
3095         }
3096         else if (handle->doubleBuffEnable && (buff2Len != 0U))
3097         {
3098             newBuff2 = handle->rxBuffAlloc(base, handle->userData, channel);
3099             if (newBuff2 == NULL)
3100             {
3101                 handle->rxBuffFree(base, newBuff1, handle->userData, channel);
3102                 isDrop = true;
3103             }
3104         }
3105         else
3106         {
3107             /* Intentional empty */
3108         }
3109 
3110         if (!isDrop)
3111         {
3112             /* Get the frame data information into Rx frame structure. */
3113             if (!handle->doubleBuffEnable)
3114             {
3115                 buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx];
3116 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3117                 buff1Addr = MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local);
3118 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
3119                 if (handle->rxMaintainEnable[channel])
3120                 {
3121                     ENET_QOS_DcacheInvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign);
3122                 }
3123                 rxFrame->rxBuffArray[index].buffer = (void *)(uint8_t *)buff1Addr;
3124                 rxFrame->rxBuffArray[index].length = buff1Len;
3125                 index++;
3126             }
3127             else
3128             {
3129                 buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx];
3130 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3131                 buff1Addr = MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local);
3132 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
3133                 if (handle->rxMaintainEnable[channel])
3134                 {
3135                     ENET_QOS_DcacheInvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign);
3136                 }
3137                 rxFrame->rxBuffArray[index].buffer = (void *)(uint8_t *)buff1Addr;
3138                 rxFrame->rxBuffArray[index].length = buff1Len;
3139                 index++;
3140 
3141                 /* If there's no data in buffer2, not add it into rxFrame */
3142                 if (buff2Len != 0U)
3143                 {
3144                     buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
3145 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3146                     buff2Addr = MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local);
3147 #endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */
3148                     if (handle->rxMaintainEnable[channel])
3149                     {
3150                         ENET_QOS_DcacheInvalidateByRange(buff2Addr, rxBdRing->rxBuffSizeAlign);
3151                     }
3152                     rxFrame->rxBuffArray[index].buffer = (void *)(uint8_t *)buff2Addr;
3153                     rxFrame->rxBuffArray[index].length = buff2Len;
3154                     index++;
3155                 }
3156             }
3157 
3158             /* Give new buffer from application to BD */
3159             if (!handle->doubleBuffEnable)
3160             {
3161                 if (handle->rxMaintainEnable[channel])
3162                 {
3163                     ENET_QOS_DcacheInvalidateByRange((uintptr_t)(uint8_t *)newBuff1, rxBdRing->rxBuffSizeAlign);
3164                 }
3165 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3166                 buff1Addr = MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)newBuff1, kMEMORY_Local2DMA);
3167 #else
3168                 buff1Addr = (uintptr_t)(uint8_t *)newBuff1;
3169 #endif
3170                 handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx] = buff1Addr;
3171                 ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable,
3172                                             handle->doubleBuffEnable);
3173             }
3174             else
3175             {
3176                 if (handle->rxMaintainEnable[channel])
3177                 {
3178                     ENET_QOS_DcacheInvalidateByRange((uintptr_t)(uint8_t *)newBuff1, rxBdRing->rxBuffSizeAlign);
3179                 }
3180 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3181                 buff1Addr = MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)newBuff1, kMEMORY_Local2DMA);
3182 #else
3183                 buff1Addr = (uintptr_t)(uint8_t *)newBuff1;
3184 #endif
3185                 handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx] = buff1Addr;
3186 
3187                 if (buff2Len != 0U)
3188                 {
3189                     if (handle->rxMaintainEnable[channel])
3190                     {
3191                         ENET_QOS_DcacheInvalidateByRange((uintptr_t)(uint8_t *)newBuff2, rxBdRing->rxBuffSizeAlign);
3192                     }
3193 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3194                     buff2Addr =
3195                         (uint32_t)MEMORY_ConvertMemoryMapAddress((uintptr_t)(uint8_t *)newBuff2, kMEMORY_Local2DMA);
3196 #else
3197                     buff2Addr = (uintptr_t)(uint8_t *)newBuff2;
3198 #endif
3199                     handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U] = buff2Addr;
3200                 }
3201                 else
3202                 {
3203                     /* If there's no data in buffer2, keep it */
3204                     buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
3205                 }
3206 
3207                 ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
3208                                             handle->rxintEnable, handle->doubleBuffEnable);
3209             }
3210             rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
3211 
3212             /* Update context BD if there is */
3213             if (isLastBuff && tsAvailable)
3214             {
3215                 rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx];
3216                 if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) != 0U)
3217                 {
3218                     ENET_QOS_StoreRxFrameTime(base, handle, rxDesc, &rxFrame->rxAttribute.timestamp);
3219                     rxFrame->rxAttribute.isTsAvail = true;
3220 
3221                     if (!handle->doubleBuffEnable)
3222                     {
3223                         buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx];
3224                         ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable,
3225                                                     handle->doubleBuffEnable);
3226                     }
3227                     else
3228                     {
3229                         buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx];
3230                         buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U];
3231                         ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr,
3232                                                     handle->rxintEnable, handle->doubleBuffEnable);
3233                     }
3234                     rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen);
3235                 }
3236             }
3237             /* Always try to start receive, in case it had stopped */
3238             rxDescTail = (uint32_t)(uintptr_t)&rxBdRing->rxBdBase[rxBdRing->rxRingLen];
3239 #if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET
3240             rxDescTail = MEMORY_ConvertMemoryMapAddress(rxDescTail, kMEMORY_Local2DMA);
3241 #endif
3242             base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = rxDescTail;
3243             base->DMA_CH[channel].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK;
3244         }
3245         else
3246         {
3247             /* Drop frame if there's no new buffer memory */
3248 
3249             /* Free the incomplete frame buffers. */
3250             while (index-- != 0U)
3251             {
3252                 handle->rxBuffFree(base, rxFrame->rxBuffArray[index].buffer, handle->userData, channel);
3253             }
3254 
3255             /* Update all left BDs of this frame from current index. */
3256             ENET_QOS_DropFrame(base, handle, channel);
3257 
3258             result = kStatus_ENET_QOS_RxFrameDrop;
3259             break;
3260         }
3261     } while (!isLastBuff);
3262 
3263     return result;
3264 }
3265 
3266 /*!
3267  * brief Gets the current ENET time from the PTP 1588 timer without IRQ disable.
3268  *
3269  * param base  ENET peripheral base address.
3270  * param second The PTP 1588 system timer second.
3271  * param nanosecond The PTP 1588 system timer nanosecond.
3272  * For the unit of the nanosecond is 1ns. so the nanosecond is the real nanosecond.
3273  */
ENET_QOS_Ptp1588GetTimerNoIRQDisable(ENET_QOS_Type * base,uint64_t * second,uint32_t * nanosecond)3274 void ENET_QOS_Ptp1588GetTimerNoIRQDisable(ENET_QOS_Type *base, uint64_t *second, uint32_t *nanosecond)
3275 {
3276     assert(second != NULL);
3277     assert(nanosecond != NULL);
3278 
3279     uint32_t high_sec[2];
3280     uint32_t sec[2];
3281 
3282     /* Get the current PTP time. */
3283     /* Since register reads are not atomic, we need to check for wraps during the read */
3284     high_sec[1] = base->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS & ENET_QOS_MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS_TSHWR_MASK;
3285 
3286     do
3287     {
3288         high_sec[0] = high_sec[1];
3289 
3290         sec[1] = base->MAC_SYSTEM_TIME_SECONDS;
3291 
3292         do
3293         {
3294             sec[0]      = sec[1];
3295             *nanosecond = base->MAC_SYSTEM_TIME_NANOSECONDS & ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_TSSS_MASK;
3296             sec[1]      = base->MAC_SYSTEM_TIME_SECONDS;
3297         } while (sec[1] != sec[0]);
3298 
3299         high_sec[1] =
3300             base->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS & ENET_QOS_MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS_TSHWR_MASK;
3301     } while (high_sec[1] != high_sec[0]);
3302 
3303     *second = ((uint64_t)high_sec[1] << 32U) | sec[1];
3304 
3305     if ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK) == 0U)
3306     {
3307         /* Binary rollover, the unit of the increment is ~ 0.465 ns. */
3308         *nanosecond = (*nanosecond * 465U) / 1000U;
3309     }
3310 }
3311 
3312 /*!
3313  * brief Gets the current ENET time from the PTP 1588 timer, get a more accurate value
3314  * with IRQ disabled during get timer.
3315  *
3316  * param base  ENET peripheral base address.
3317  * param second The PTP 1588 system timer second.
3318  * param nanosecond The PTP 1588 system timer nanosecond.
3319  * For the unit of the nanosecond is 1ns. so the nanosecond is the real nanosecond.
3320  */
ENET_QOS_Ptp1588GetTimer(ENET_QOS_Type * base,uint64_t * second,uint32_t * nanosecond)3321 void ENET_QOS_Ptp1588GetTimer(ENET_QOS_Type *base, uint64_t *second, uint32_t *nanosecond)
3322 {
3323     uint32_t primask;
3324 
3325     /* Disables the interrupt. */
3326     primask = DisableGlobalIRQ();
3327 
3328     ENET_QOS_Ptp1588GetTimerNoIRQDisable(base, second, nanosecond);
3329 
3330     /* Enables the interrupt. */
3331     EnableGlobalIRQ(primask);
3332 }
3333 
3334 /*!
3335  * brief Coreect the ENET PTP 1588 timer in coarse method.
3336  *
3337  * param base  ENET peripheral base address.
3338  * param operation The system time operation, refer to "enet_qos_systime_op"
3339  * param second The correction second.
3340  * param nanosecond The correction nanosecond.
3341  */
ENET_QOS_Ptp1588CorrectTimerInCoarse(ENET_QOS_Type * base,enet_qos_systime_op operation,uint32_t second,uint32_t nanosecond)3342 status_t ENET_QOS_Ptp1588CorrectTimerInCoarse(ENET_QOS_Type *base,
3343                                               enet_qos_systime_op operation,
3344                                               uint32_t second,
3345                                               uint32_t nanosecond)
3346 {
3347     uint32_t corrSecond = second;
3348     uint32_t corrNanosecond;
3349     status_t result = kStatus_Success;
3350 
3351     /* Set the system timer. */
3352     if ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK) != 0U)
3353     {
3354         if (operation == kENET_QOS_SystimeSubtract)
3355         {
3356             /* Set with the complement of the sub-second. */
3357             corrSecond     = ENET_QOS_MAC_SYSTEM_TIME_SECONDS_UPDATE_TSS_MASK - (second - 1U);
3358             corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_ADDSUB_MASK |
3359                              ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(ENET_QOS_NANOSECS_ONESECOND - nanosecond);
3360         }
3361         else
3362         {
3363             corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(nanosecond);
3364         }
3365     }
3366     else
3367     {
3368         nanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS_MASK / ENET_QOS_NANOSECS_ONESECOND * nanosecond;
3369         if (operation == kENET_QOS_SystimeSubtract)
3370         {
3371             /* Set with the complement of the sub-second. */
3372             corrSecond     = ENET_QOS_MAC_SYSTEM_TIME_SECONDS_UPDATE_TSS_MASK - (second - 1U);
3373             corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_ADDSUB_MASK |
3374                              ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(
3375                                  ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS_MASK + 1U - nanosecond);
3376         }
3377         else
3378         {
3379             corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(nanosecond);
3380         }
3381     }
3382 
3383     base->MAC_SYSTEM_TIME_SECONDS_UPDATE     = corrSecond;
3384     base->MAC_SYSTEM_TIME_NANOSECONDS_UPDATE = corrNanosecond;
3385 
3386     /* Update the timer. */
3387     base->MAC_TIMESTAMP_CONTROL |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSUPDT_MASK;
3388 
3389     /* Wait for update finish */
3390     result = ENET_QOS_PollStatusFlag(&(base->MAC_TIMESTAMP_CONTROL), ENET_QOS_MAC_TIMESTAMP_CONTROL_TSUPDT_MASK, 0U);
3391 
3392     return result;
3393 }
3394 
3395 /*!
3396  * brief Correct the ENET PTP 1588 timer in fine method.
3397  *
3398  *
3399  * param base  ENET peripheral base address.
3400  * param addend The addend value to be set in the fine method
3401  * note Should take refer to the chapter "System time correction" and
3402  * see the description for the "fine correction method".
3403  */
ENET_QOS_Ptp1588CorrectTimerInFine(ENET_QOS_Type * base,uint32_t addend)3404 status_t ENET_QOS_Ptp1588CorrectTimerInFine(ENET_QOS_Type *base, uint32_t addend)
3405 {
3406     status_t result = kStatus_Success;
3407 
3408     base->MAC_TIMESTAMP_ADDEND = addend;
3409     base->MAC_TIMESTAMP_CONTROL |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK;
3410 
3411     result = ENET_QOS_PollStatusFlag(&(base->MAC_TIMESTAMP_CONTROL), ENET_QOS_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK, 0U);
3412 
3413     return result;
3414 }
3415 
3416 /*!
3417  * @brief Sets the ENET OQS PTP 1588 PPS target time registers.
3418  *
3419  * param base  ENET QOS peripheral base address.
3420  * param instance The ENET QOS PTP PPS instance.
3421  * param seconds The target seconds.
3422  * param nanoseconds The target nanoseconds.
3423  */
ENET_QOS_Ptp1588PpsSetTrgtTime(ENET_QOS_Type * base,enet_qos_ptp_pps_instance_t instance,uint32_t seconds,uint32_t nanoseconds)3424 status_t ENET_QOS_Ptp1588PpsSetTrgtTime(ENET_QOS_Type *base,
3425                                         enet_qos_ptp_pps_instance_t instance,
3426                                         uint32_t seconds,
3427                                         uint32_t nanoseconds)
3428 {
3429     uint32_t *mac_pps_trgt_ns;
3430     uint32_t *mac_pps_trgt_s;
3431 
3432     mac_pps_trgt_ns = (uint32_t *)((uintptr_t)&base->MAC_PPS0_TARGET_TIME_NANOSECONDS + 0x10U * (uint32_t)instance);
3433     mac_pps_trgt_s  = (uint32_t *)((uintptr_t)&base->MAC_PPS0_TARGET_TIME_SECONDS + 0x10U * (uint32_t)instance);
3434 
3435     if ((*mac_pps_trgt_ns & ENET_QOS_MAC_PPS0_TARGET_TIME_NANOSECONDS_TRGTBUSY0_MASK) != 0U)
3436     {
3437         return kStatus_ENET_QOS_TrgtBusy;
3438     }
3439 
3440     *mac_pps_trgt_ns = ENET_QOS_MAC_PPS0_TARGET_TIME_NANOSECONDS_TTSL0(nanoseconds);
3441     *mac_pps_trgt_s  = ENET_QOS_MAC_PPS0_TARGET_TIME_SECONDS_TSTRH0(seconds);
3442 
3443     return kStatus_Success;
3444 }
3445 
ENET_QOS_EstReadWriteWord(ENET_QOS_Type * base,uint32_t addr,uint32_t * data,uint8_t gcrr,uint8_t read,uint8_t dbgm)3446 static status_t ENET_QOS_EstReadWriteWord(
3447     ENET_QOS_Type *base, uint32_t addr, uint32_t *data, uint8_t gcrr, uint8_t read, uint8_t dbgm)
3448 {
3449     uint32_t ctrl;
3450     int retry = 10;
3451 
3452     ctrl = ENET_QOS_MTL_EST_GCL_CONTROL_ADDR(addr) | ENET_QOS_MTL_EST_GCL_CONTROL_SRWO(1) |
3453            ENET_QOS_MTL_EST_GCL_CONTROL_DBGM(dbgm) | ENET_QOS_MTL_EST_GCL_CONTROL_GCRR(gcrr);
3454 
3455     if (read != 0U)
3456     {
3457         ctrl |= ENET_QOS_MTL_EST_GCL_CONTROL_R1W0(1);
3458     }
3459     else
3460     {
3461         base->MTL_EST_GCL_DATA = *data;
3462     }
3463 
3464     base->MTL_EST_GCL_CONTROL = ctrl;
3465 
3466     while ((base->MTL_EST_GCL_CONTROL & ENET_QOS_MTL_EST_GCL_CONTROL_SRWO_MASK) != 0U)
3467     {
3468         if (retry-- < 0)
3469         {
3470             return kStatus_Timeout;
3471         }
3472         SDK_DelayAtLeastUs(1, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
3473     }
3474 
3475     if (read != 0U)
3476     {
3477         *data = base->MTL_EST_GCL_DATA;
3478     }
3479 
3480     if ((base->MTL_EST_GCL_CONTROL & ENET_QOS_MTL_EST_GCL_CONTROL_ERR0_MASK) != 0U)
3481     {
3482         return kStatus_ENET_QOS_Est_SwListWriteAbort;
3483     }
3484 
3485     return kStatus_Success;
3486 }
3487 
ENET_QOS_EstProgramWord(ENET_QOS_Type * base,uint32_t addr,uint32_t * data,uint8_t gcrr)3488 static status_t ENET_QOS_EstProgramWord(ENET_QOS_Type *base, uint32_t addr, uint32_t *data, uint8_t gcrr)
3489 {
3490     return ENET_QOS_EstReadWriteWord(base, addr, data, gcrr, 0, 0);
3491 }
3492 
ENET_QOS_EstReadWord(ENET_QOS_Type * base,uint32_t addr,uint32_t * data,uint8_t gcrr,uint8_t dbgm)3493 static status_t ENET_QOS_EstReadWord(ENET_QOS_Type *base, uint32_t addr, uint32_t *data, uint8_t gcrr, uint8_t dbgm)
3494 {
3495     return ENET_QOS_EstReadWriteWord(base, addr, data, gcrr, 1, dbgm);
3496 }
3497 
3498 /*!
3499  * @brief Program Gate Control List.
3500  *
3501  * This function is used to program the Enhanced Scheduled Transmisson. (IEEE802.1Qbv)
3502  *
3503  * @param base  ENET peripheral base address..
3504  * @param gcl Pointer to the Gate Control List structure.
3505  * @param ptpClk_Hz frequency of the PTP clock.
3506  */
ENET_QOS_EstProgramGcl(ENET_QOS_Type * base,enet_qos_est_gcl_t * gcl,uint32_t ptpClk_Hz)3507 status_t ENET_QOS_EstProgramGcl(ENET_QOS_Type *base, enet_qos_est_gcl_t *gcl, uint32_t ptpClk_Hz)
3508 {
3509     assert(gcl != NULL);
3510     uint32_t i, control, data;
3511     enet_qos_est_gate_op_t *gateOp;
3512     status_t rc;
3513 
3514 #define EST_MAX_INTERVAL ((1UL << ENET_QOS_EST_WID) - 1U)
3515 #define EST_MAX_GATE     ((1UL << (32U - ENET_QOS_EST_WID)) - 1U)
3516 
3517     if (!gcl->enable)
3518     {
3519         goto exit;
3520     }
3521 
3522     /* Sanity checks */
3523     if (gcl->numEntries > ENET_QOS_EST_DEP)
3524     {
3525         return kStatus_ENET_QOS_Est_InvalidParameter;
3526     }
3527 
3528     if (gcl->opList == NULL)
3529     {
3530         return kStatus_ENET_QOS_Est_InvalidParameter;
3531     }
3532 
3533     gateOp = gcl->opList;
3534 
3535     for (i = 0; i < gcl->numEntries; i++)
3536     {
3537         if (gateOp->interval > EST_MAX_INTERVAL)
3538         {
3539             return kStatus_ENET_QOS_Est_InvalidParameter;
3540         }
3541         if (gateOp->gate > EST_MAX_GATE)
3542         {
3543             return kStatus_ENET_QOS_Est_InvalidParameter;
3544         }
3545         gateOp++;
3546     }
3547 
3548     /* Check if sw list is busy */
3549     if ((base->MTL_EST_CONTROL & ENET_QOS_MTL_EST_CONTROL_SSWL_MASK) != 0U)
3550     {
3551         return kStatus_ENET_QOS_Est_SwListBusy;
3552     }
3553 
3554     gateOp = gcl->opList;
3555 
3556     for (i = 0; i < gcl->numEntries; i++)
3557     {
3558         data = gateOp->interval | (gateOp->gate << ENET_QOS_EST_WID);
3559         rc   = ENET_QOS_EstProgramWord(base, i, &data, 0);
3560         if (rc != kStatus_Success)
3561         {
3562             return rc;
3563         }
3564 
3565         gateOp++;
3566     }
3567 
3568     /* BTR High */
3569     data = (uint32_t)(gcl->baseTime >> 32U);
3570     rc   = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_btr_high, &data, 1U);
3571     if (rc != kStatus_Success)
3572     {
3573         return rc;
3574     }
3575 
3576     /* BTR Low */
3577     data = (uint32_t)gcl->baseTime;
3578     rc   = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_btr_low, &data, 1);
3579     if (rc != kStatus_Success)
3580     {
3581         return rc;
3582     }
3583 
3584     /* CTR High */
3585     data = (uint32_t)(gcl->cycleTime >> 32U);
3586     rc   = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_ctr_high, &data, 1);
3587     if (rc != kStatus_Success)
3588     {
3589         return rc;
3590     }
3591 
3592     /* CTR Low */
3593     data = (uint32_t)gcl->cycleTime;
3594     rc   = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_ctr_low, &data, 1);
3595     if (rc != kStatus_Success)
3596     {
3597         return rc;
3598     }
3599 
3600     /* TER */
3601     data = gcl->extTime;
3602     rc   = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_ter, &data, 1);
3603     if (rc != kStatus_Success)
3604     {
3605         return rc;
3606     }
3607 
3608     /* LLR */
3609     data = gcl->numEntries;
3610     rc   = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_llr, &data, 1);
3611     if (rc != kStatus_Success)
3612     {
3613         return rc;
3614     }
3615 
3616 exit:
3617     control = base->MTL_EST_CONTROL;
3618 
3619     if (gcl->enable)
3620     {
3621         control &= ~ENET_QOS_MTL_EST_CONTROL_PTOV_MASK;
3622         control |= ENET_QOS_MTL_EST_CONTROL_SSWL_MASK | ENET_QOS_MTL_EST_CONTROL_EEST_MASK |
3623                    ENET_QOS_MTL_EST_CONTROL_PTOV((1000000000U / ptpClk_Hz) * 6U);
3624     }
3625     else
3626     {
3627         control &= ~ENET_QOS_MTL_EST_CONTROL_EEST_MASK;
3628     }
3629 
3630     base->MTL_EST_CONTROL = control;
3631 
3632     return kStatus_Success;
3633 }
3634 
3635 /*!
3636  * @brief Read Gate Control List.
3637  *
3638  * This function is used to read the Enhanced Scheduled Transmisson list. (IEEE802.1Qbv)
3639  *
3640  * @param base  ENET peripheral base address..
3641  * @param gcl Pointer to the Gate Control List structure.
3642  * @param listLen length of the provided opList array in gcl structure.
3643  * @param hwList Boolean if True read HW list, false read SW list.
3644  */
ENET_QOS_EstReadGcl(ENET_QOS_Type * base,enet_qos_est_gcl_t * gcl,uint32_t listLen,bool hwList)3645 status_t ENET_QOS_EstReadGcl(ENET_QOS_Type *base, enet_qos_est_gcl_t *gcl, uint32_t listLen, bool hwList)
3646 {
3647     assert(gcl != NULL);
3648     assert(gcl->opList != NULL);
3649     uint8_t dbgm = 0;
3650     uint32_t data, i;
3651     enet_qos_est_gate_op_t *gateOp;
3652     status_t rc;
3653 
3654     if (hwList == true)
3655     {
3656         dbgm = 1;
3657     }
3658 
3659     /* LLR */
3660     rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_llr, &data, 1, dbgm);
3661     if (rc != kStatus_Success)
3662     {
3663         return rc;
3664     }
3665 
3666     gcl->numEntries = data;
3667 
3668     if (gcl->numEntries > listLen)
3669     {
3670         return kStatus_ENET_QOS_Est_InvalidParameter;
3671     }
3672 
3673     /* BTR High */
3674     rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_btr_high, &data, 1, dbgm);
3675     if (rc != kStatus_Success)
3676     {
3677         return rc;
3678     }
3679 
3680     gcl->baseTime = (uint64_t)data << 32U;
3681 
3682     /* BTR Low */
3683     rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_btr_low, &data, 1, dbgm);
3684     if (rc != kStatus_Success)
3685     {
3686         return rc;
3687     }
3688 
3689     gcl->baseTime |= data;
3690 
3691     /* CTR High */
3692     rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_ctr_high, &data, 1, dbgm);
3693     if (rc != kStatus_Success)
3694     {
3695         return rc;
3696     }
3697 
3698     gcl->cycleTime = (uint64_t)data << 32U;
3699 
3700     /* CTR Low */
3701     rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_ctr_low, &data, 1, dbgm);
3702     if (rc != kStatus_Success)
3703     {
3704         return rc;
3705     }
3706 
3707     gcl->cycleTime |= data;
3708 
3709     /* TER */
3710     rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_ter, &data, 1, dbgm);
3711     if (rc != kStatus_Success)
3712     {
3713         return rc;
3714     }
3715 
3716     gcl->extTime = data;
3717 
3718     gateOp = gcl->opList;
3719 
3720     for (i = 0; i < gcl->numEntries; i++)
3721     {
3722         rc = ENET_QOS_EstReadWord(base, i, &data, 0, dbgm);
3723         if (rc != kStatus_Success)
3724         {
3725             return rc;
3726         }
3727 
3728         gateOp->interval = data & (EST_MAX_INTERVAL);
3729         gateOp->gate     = data >> ENET_QOS_EST_WID;
3730         gateOp++;
3731     }
3732 
3733     return kStatus_Success;
3734 }
3735 
3736 /*!
3737  * brief Read flexible rx parser configuration at specified index.
3738  *
3739  * This function is used to read flexible rx parser configuration at specified index.
3740  *
3741  * param base  ENET peripheral base address..
3742  * param rxpConfig The rx parser configuration pointer.
3743  * param entryIndex The rx parser entry index to read, start from 0.
3744  * retval kStatus_Success Configure rx parser success.
3745  * retval kStatus_ENET_QOS_Timeout Poll status flag timeout.
3746  */
ENET_QOS_ReadRxParser(ENET_QOS_Type * base,enet_qos_rxp_config_t * rxpConfig,uint16_t entryIndex)3747 status_t ENET_QOS_ReadRxParser(ENET_QOS_Type *base, enet_qos_rxp_config_t *rxpConfig, uint16_t entryIndex)
3748 {
3749     assert(rxpConfig != NULL);
3750     assert(entryIndex < ENET_QOS_RXP_ENTRY_COUNT);
3751 
3752     uint32_t *dataPtr;
3753     uint8_t entrySize = sizeof(enet_qos_rxp_config_t) / sizeof(uint32_t);
3754     uint32_t value    = 0U;
3755     status_t result   = kStatus_Success;
3756 
3757     /* Wait hardware not busy */
3758     result = ENET_QOS_PollStatusFlag(&(base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS),
3759                                      ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U);
3760     if (kStatus_Success != result)
3761     {
3762         return result;
3763     }
3764 
3765     for (uint8_t i = 0; i < entrySize; i++)
3766     {
3767         /* Read address. */
3768         value = ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_ADDR((uint32_t)entrySize * entryIndex + i);
3769 
3770         /* Issue read command. */
3771         value &= ~ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_WRRDN_MASK;
3772         base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value;
3773 
3774         /* Start Read */
3775         value |= ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK;
3776         base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value;
3777 
3778         /* Wait hardware not busy */
3779         result = ENET_QOS_PollStatusFlag(&base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS,
3780                                          ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U);
3781         if (kStatus_Success != result)
3782         {
3783             return result;
3784         }
3785 
3786         dataPtr = (uint32_t *)(void *)&rxpConfig[entryIndex];
3787         dataPtr = &dataPtr[i];
3788         /* Read data */
3789         *dataPtr = base->MTL_RXP_INDIRECT_ACC_DATA;
3790     }
3791 
3792     return result;
3793 }
3794 
3795 /*!
3796  * brief Configure flexible rx parser.
3797  *
3798  * This function is used to configure the flexible rx parser table.
3799  *
3800  * param base  ENET peripheral base address..
3801  * param rxpConfig The rx parser configuration pointer.
3802  * param entryCount The rx parser entry count.
3803  * retval kStatus_Success Configure rx parser success.
3804  * retval kStatus_ENET_QOS_Timeout Poll status flag timeout.
3805  */
ENET_QOS_ConfigureRxParser(ENET_QOS_Type * base,enet_qos_rxp_config_t * rxpConfig,uint16_t entryCount)3806 status_t ENET_QOS_ConfigureRxParser(ENET_QOS_Type *base, enet_qos_rxp_config_t *rxpConfig, uint16_t entryCount)
3807 {
3808     assert(rxpConfig != NULL);
3809     assert(entryCount <= ENET_QOS_RXP_ENTRY_COUNT);
3810 
3811     uint32_t *dataPtr;
3812     uint32_t entrySize = sizeof(enet_qos_rxp_config_t) / sizeof(uint32_t);
3813     uint32_t value     = 0U;
3814     status_t result    = kStatus_Success;
3815     bool enableRx      = false;
3816 
3817     /* Disable the MAC rx. */
3818     if (0U != (base->MAC_CONFIGURATION & ENET_QOS_MAC_CONFIGURATION_RE_MASK))
3819     {
3820         base->MAC_CONFIGURATION &= ~ENET_QOS_MAC_CONFIGURATION_RE_MASK;
3821         enableRx = true;
3822     }
3823 
3824     /* Disable frame parser. */
3825     result = ENET_QOS_EnableRxParser(base, false);
3826 
3827     if (kStatus_Success != result)
3828     {
3829         return result;
3830     }
3831 
3832     for (uint8_t count = 0; count < entryCount; count++)
3833     {
3834         for (uint8_t i = 0; i < entrySize; i++)
3835         {
3836             /* Wait hardware not busy */
3837             result = ENET_QOS_PollStatusFlag(&base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS,
3838                                              ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U);
3839             if (kStatus_Success != result)
3840             {
3841                 return result;
3842             }
3843 
3844             dataPtr = (uint32_t *)(void *)&rxpConfig[count];
3845             dataPtr = &dataPtr[i];
3846 
3847             /* Write data before issue write command */
3848             base->MTL_RXP_INDIRECT_ACC_DATA = *dataPtr;
3849 
3850             /* Write address and issue write command */
3851             value = ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_ADDR(entrySize * count + i);
3852             // base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value;
3853 
3854             value |= ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_WRRDN_MASK;
3855             base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value;
3856 
3857             /* Start write */
3858             value |= ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK;
3859             base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value;
3860         }
3861     }
3862 
3863     /* Wait hardware not busy */
3864     result = ENET_QOS_PollStatusFlag(&(base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS),
3865                                      ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U);
3866     if (kStatus_Success != result)
3867     {
3868         return result;
3869     }
3870 
3871     /* Program NVE and NPE. */
3872     value = base->MTL_RXP_CONTROL_STATUS;
3873     value &= ~(ENET_QOS_MTL_RXP_CONTROL_STATUS_NVE_MASK | ENET_QOS_MTL_RXP_CONTROL_STATUS_NPE_MASK);
3874 
3875     value |= ENET_QOS_MTL_RXP_CONTROL_STATUS_NPE((uint32_t)entryCount - 1U);
3876     if (entryCount < 3U)
3877     {
3878         value |= ENET_QOS_MTL_RXP_CONTROL_STATUS_NVE(2U);
3879     }
3880     else
3881     {
3882         value |= ENET_QOS_MTL_RXP_CONTROL_STATUS_NVE((uint32_t)entryCount - 1U);
3883     }
3884 
3885     base->MTL_RXP_CONTROL_STATUS = value;
3886 
3887     /* Enable frame parser. */
3888     result = ENET_QOS_EnableRxParser(base, true);
3889 
3890     /* Enable Receive */
3891     if (enableRx)
3892     {
3893         base->MAC_CONFIGURATION |= ENET_QOS_MAC_CONFIGURATION_RE_MASK;
3894     }
3895 
3896     return result;
3897 }
3898 
3899 /*!
3900  * brief Gets statistical data in transfer.
3901  *
3902  * param base  ENET_QOS peripheral base address.
3903  * param statistics The statistics structure pointer.
3904  */
ENET_QOS_GetStatistics(ENET_QOS_Type * base,enet_qos_transfer_stats_t * statistics)3905 void ENET_QOS_GetStatistics(ENET_QOS_Type *base, enet_qos_transfer_stats_t *statistics)
3906 {
3907     /* Rx statistics */
3908     statistics->statsRxFrameCount      = base->MAC_RX_PACKETS_COUNT_GOOD_BAD;
3909     statistics->statsRxCrcErr          = base->MAC_RX_CRC_ERROR_PACKETS;
3910     statistics->statsRxAlignErr        = base->MAC_RX_ALIGNMENT_ERROR_PACKETS;
3911     statistics->statsRxLengthErr       = base->MAC_RX_LENGTH_ERROR_PACKETS;
3912     statistics->statsRxFifoOverflowErr = base->MAC_RX_FIFO_OVERFLOW_PACKETS;
3913 
3914     /* Tx statistics */
3915     statistics->statsTxFrameCount      = base->MAC_TX_PACKET_COUNT_GOOD_BAD;
3916     statistics->statsTxFifoUnderRunErr = base->MAC_TX_UNDERFLOW_ERROR_PACKETS;
3917 }
3918 
3919 /*!
3920  * brief The ENET IRQ handler.
3921  *
3922  * param base  ENET peripheral base address.
3923  * param handle The ENET handler pointer.
3924  */
ENET_QOS_CommonIRQHandler(ENET_QOS_Type * base,enet_qos_handle_t * handle)3925 void ENET_QOS_CommonIRQHandler(ENET_QOS_Type *base, enet_qos_handle_t *handle)
3926 {
3927     /* Check for the interrupt source type. */
3928     /* DMA CHANNEL 0. */
3929     if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC0IS_MASK) != 0U)
3930     {
3931         uint32_t flag = base->DMA_CH[0].DMA_CHX_STAT;
3932         if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U)
3933         {
3934             base->DMA_CH[0].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3935             if (handle->callback != NULL)
3936             {
3937                 handle->callback(base, handle, kENET_QOS_RxIntEvent, 0, handle->userData);
3938             }
3939         }
3940         if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U)
3941         {
3942             base->DMA_CH[0].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3943             ENET_QOS_ReclaimTxDescriptor(base, handle, 0);
3944         }
3945     }
3946 
3947     /* DMA CHANNEL 1. */
3948     if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC1IS_MASK) != 0U)
3949     {
3950         uint32_t flag = base->DMA_CH[1].DMA_CHX_STAT;
3951         if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U)
3952         {
3953             base->DMA_CH[1].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3954             if (handle->callback != NULL)
3955             {
3956                 handle->callback(base, handle, kENET_QOS_RxIntEvent, 1, handle->userData);
3957             }
3958         }
3959         if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U)
3960         {
3961             base->DMA_CH[1].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3962             ENET_QOS_ReclaimTxDescriptor(base, handle, 1);
3963         }
3964     }
3965 
3966     /* DMA CHANNEL 2. */
3967     if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC2IS_MASK) != 0U)
3968     {
3969         uint32_t flag = base->DMA_CH[2].DMA_CHX_STAT;
3970         if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U)
3971         {
3972             base->DMA_CH[2].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3973             if (handle->callback != NULL)
3974             {
3975                 handle->callback(base, handle, kENET_QOS_RxIntEvent, 2, handle->userData);
3976             }
3977         }
3978         if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U)
3979         {
3980             base->DMA_CH[2].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3981             ENET_QOS_ReclaimTxDescriptor(base, handle, 2);
3982         }
3983     }
3984 
3985     /* DMA CHANNEL 3. */
3986     if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC3IS_MASK) != 0U)
3987     {
3988         uint32_t flag = base->DMA_CH[3].DMA_CHX_STAT;
3989         if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U)
3990         {
3991             base->DMA_CH[3].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
3992             if (handle->callback != NULL)
3993             {
3994                 handle->callback(base, handle, kENET_QOS_RxIntEvent, 3, handle->userData);
3995             }
3996         }
3997         if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U)
3998         {
3999             base->DMA_CH[3].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK;
4000             ENET_QOS_ReclaimTxDescriptor(base, handle, 3);
4001         }
4002     }
4003 
4004     /* MAC TIMESTAMP. */
4005     if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_MACIS_MASK) != 0U)
4006     {
4007         if ((base->MAC_INTERRUPT_STATUS & ENET_QOS_MAC_INTERRUPT_STATUS_TSIS_MASK) != 0U)
4008         {
4009             if (handle->callback != NULL)
4010             {
4011                 handle->callback(base, handle, kENET_QOS_TimeStampIntEvent, 0, handle->userData);
4012             }
4013         }
4014     }
4015     SDK_ISR_EXIT_BARRIER;
4016 }
4017 
4018 #if defined(ENET_QOS)
4019 void ENET_QOS_DriverIRQHandler(void);
ENET_QOS_DriverIRQHandler(void)4020 void ENET_QOS_DriverIRQHandler(void)
4021 {
4022     s_enetqosIsr(ENET_QOS, s_ENETHandle[0]);
4023 }
4024 #endif
4025 
4026 #if defined(CONNECTIVITY__ENET_QOS)
4027 void CONNECTIVITY_EQOS_INT_DriverIRQHandler(void);
CONNECTIVITY_EQOS_INT_DriverIRQHandler(void)4028 void CONNECTIVITY_EQOS_INT_DriverIRQHandler(void)
4029 {
4030     s_enetqosIsr(CONNECTIVITY__ENET_QOS, s_ENETHandle[0]);
4031 }
4032 #endif
4033