/** * @file module_driver_enet.c * @author Flagchip * @brief ENET driver source code * @version 2.6.0 * @date 2025-12-24 * * SDK Version: 2.6.0 * * @copyright Copyright (c) 2020-2024 Flagchip Semiconductors Co., Ltd. * */ /********************************************************************************************************** * Revision History: * Version Date Initials CR# Descriptions * --------- ---------- ------------ ---------- --------------- * 2.0.0 2024-10-12 Flagchip085 N/A First version * 2.6.0 2025-12-24 Flagchip085 N/A Support buffer dynamic allocation *******************************************************************************************************/ /** ********************************************************************************************************* How to use this driver ********************************************************************************************************* * [*] Initialize ENET IO before using this driver. * Initialize system clocks before using this driver. * Enable ENET PCC clock before using this driver. * Configure NVIC for ENET interrupts before using this driver. * * [*] Initialize the MDIO bus, if you want to configure the PHY before Enet_Init, * For example, when the RMII reference clock is provided by PHY. * The MDIO bus will be Initialized again by Enet_Init. * [**] Call Enet_MDIODefaultConfig to get SMI bus default configuration. * [**] Modify the ENET_MiiConfigType value according to the actual situation. * [**] Call Enet_MDIOInit to initialize the MDIO bus. * [**] Call Enet_MDIORead and Enet_MDIOWrite to read and write PHY registers. * * [*] Call Enet_DefaultConfig API to get default ENET configuration and modify the ENET_ConfigType value * according to the actual situation. * * [*] Call Enet_Init API to initialize the ENET driver handle and ENET peripheral. * Note: * 1. The transmit/receive descriptors must be located in SRAM non-cacheable section. * 2. The transmit/receive buffers can be located in DTCM, SRAM non-cacheable or SRAM cacheable section, * and the limits are as follows: * Cache-able SRAM(write-through, no-write-allocate), this mode is recommanded. * Cache-able SRAM(write-back, write-allocate), buffers address and size must be cache-line(32 bytes) * aligned and the CacheWriteBack in ENET_DescConfigType must be set to true. * 3. If using zero copy mode, define ENET_BUFFER_DYNAMIC_ALLOCATION STD_ON, see the macro default definition * in module_driver_enet.h for details. * * [*] Start transmission and reception: * [**] Call Enet_Start to start transmission. * Enet_SendFrame : Send frame. * TxComplete will be called On transmit complete,if TxComplete is assigned. * TxCompleteWait will be called to suspend current task,which can be resumed by TxComplete. * For example: * If you need to get the transmit time stamp for time synchronization,you can call sem_post in TxComplete * and call sem_wait in TxCompleteWait,the valid time stamp will be saved in ENET_TxOptionType. * * Enet_ReadFrame : Receive frame. * When a new packet arrives,RxReady will be called if RxReady is assigned. * User call Enet_ReadFrame to get the frame buffer and frame information. * Enet_BuildRxDescriptors: Build DMA Rx descriptors. * After Enet_ReadFrame,Enet_BuildRxDescriptors must be called to free the descriptors and buffers to DMA. * * [*] Call Enet_DeInit API to stop and reset the ENET driver. * * [*] ENET events: EventCallback will be called when the following events triggered: * * [*] IEEE1588 API usage. * [**] Enet_PTPDefaultConfig to get PTP default configuration and modify the Enet_PTPConfigType value * according to the actual situation. * * [**] CALL Enet_PTPStart to start time stamp counter. * * [**] Get the transmit time stamp of PTP packets by reading TimeStamp in ENET_TxOptionType. * * [**] Get the receive time stamp of PTP packets by reading TimeStamp in ENET_RxInfoType. * * [**] The following APIs are used by PTP application for time synchronization: * Enet_PTPGetTime * Enet_PTPSetTime * Enet_PTPUpdateTime * Enet_PTPAdjustFrequency * * [**] Call the following APIs to configure the PPS output mode. * Enet_PTPFixedPPSOut * Enet_PTPFlexiblePPSOut * * [**] Call Enet_PTPStop to stop time stamp counter. * * [**] IEEE1588 events: EventCallback will be called when the following events triggered: * ENET_EVENT_TARGET_TIME0_REACHED * ENET_EVENT_TARGET_TIME0_ERROR * ENET_EVENT_TARGET_TIME1_REACHED * ENET_EVENT_TARGET_TIME1_ERROR * ENET_EVENT_TARGET_TIME2_REACHED * ENET_EVENT_TARGET_TIME2_ERROR * ENET_EVENT_TARGET_TIME3_REACHED * ENET_EVENT_TARGET_TIME3_ERROR * * [*] There are two ways to register callback functions: * [**] Initialize callback functions in ENET_ConfigType. * [**] Register functions dynamically by the following API: * Enet_RegisterEventCallback * Enet_RegisterRxCompleteCallback * Enet_RegisterTxCompleteCallback * Enet_RegisterWaitTxCompleteCallback * * [*] MAC layer2 filter * [**] After Enet_Init, MAC layer 2 filter is enabled as default configuration: * UNICAST is filtered using perfect match with destination MAC address. * MULTICAST is filtered using hash table match with destination MAC address. * [**] You can modify the configuration by the following API: * Enet_DefaultMACFilter : Get default configurations. * Enet_GetMACFilter : Get current filter configurations. * Enet_SetMACFilter : Set MAC layer 2 filter configurations. * [**] Enet_SetMacHashTable * If hash table filter is enabled, use Enet_SetMacHashTable to set hash table. * * [*] MAC layer3 layer4 filter.There are 4 group of layer3 layer4 filters, * and the filters must be enabled manually using the following API. * Enet_DefaultL3L4Filter : Get layer3 layer4 filter default configurations. * Enet_GetL3L4Filter : Get layer3 layer4 filter current configurations. * Enet_SetL3L4Filter : Set layer3 layer4 filter configurations. * Enet_EnableL3L4Filter : Enable layer3 layer4 filter. * * [*] MAC VLAN filter.There are 4 groups of perfect filters,and a hash table filter. * The VLAN perfect filter groups and hash table filter can be enabled simultaneously. * [**]Complete the following steps To use MAC VLAN filter * Enet_EnableVlanFilter : Enable VLAN filter with ENET_VlanFilterConfigType. * Enet_SetVlanPerfectFilter : Set VLAN perfect filter configurations of any group. * Enet_SetVlanHashTable: Add VLAN tag to hash table if VLAN hash table is enabled. * [**] Get VLAN filter configurations and perfect filters parameters * Enet_GetVlanFilterConfig : Get VLAN filter global configurations * Enet_GetVlanPerfectFilter : Get VLAN perfect filter parameters of specified group. * * [*] VLAN tag insertion delete replacement. There are two ways of transmit VLAN tag control. * [**] Enabling VLAN insertion, replacement, or deletion for all packets. * Enet_SetTxOuterVlanConfig : Set outer VLAN tag control configuration. * Enet_SetTxInnerVlanConfig : Set inner VLAN tag control configuration. * Enet_SetTxOuterVlanChannelBasedInsertion : Set channel based VLAN tag insertion. * * [**] Enabling VLAN insertion, replacement, or deletion for selective packets controlled by DMA descriptors. * Set Attributes of transmit frames with ENET_TX_ATTRIBUTES_INNER_VLAN_TAG_CTRL. * Fill VlanConfig in ENET_TxOptionType. * If use inner VLAN tag, set Attributes ENET_TX_ATTRIBUTES_INNER_VLAN_TAG_CTRL and * fill InnerVlanConfig similarly. * VLAN tag will be inserted delete of replaced when frames transmitted. * *********************************************************************************************************/ #include "module_driver_enet.h" #if ENET_INSTANCE_COUNT > 0u #ifndef ENET_DEV_ERROR_REPORT #define ENET_DEV_ERROR_REPORT STD_OFF #endif /** @brief MAC hash table index shift */ #define ENET_MAC_HASH_TABLE_INDEX_SHIFT (37u - ENET_MAC_HASH_WIDTH_BITS) /** @brief MAC hash table index mask */ #define ENET_MAC_HASH_TABLE_INDEX_MASK (0x7u) /** @brief MAC hash table bit shift */ #define ENET_MAC_HASH_TABLE_BIT_SHIFT (32u - ENET_MAC_HASH_WIDTH_BITS) /** @brief MAC hash table bit mask */ #define ENET_MAC_HASH_TABLE_BIT_MASK (0x1Fu) /** @brief VLAN hash table bit shift */ #define ENET_VLAN_HASH_TABLE_BIT_SHIFT (32u - ENET_VLAN_HASH_WIDTH_BITS) /** @brief VLAN hash table bit mask */ #define ENET_VLAN_HASH_TABLE_BIT_MASK (0xFu) #define ENET_GET_DESINFO_PTR(pDesc, mode) \ ((ENET_DMADescType *)(((mode) == ENET_ENHANCED_DES_TYPE) ? (&((ENET_DMAEnhancedDescType *)(pDesc))->Des0) : (pDesc))) static void Enet_SystemConfig(const ENET_ConfigType *pConfig); static ENET_StatusType Enet_SoftwareReset(ENET_Type *pEnetBase, uint32_t u16Timeout); static void Enet_DMAInit(ENET_HandleType *pEnetHandle, const ENET_DMAConfigType *pDmaConfig); static void Enet_MACInit(ENET_HandleType *pEnetHandle, const ENET_MACConfigType *pMACConfig, ENET_MAC_SpeedType eSpeed, ENET_MAC_DuplexModeType eDuplexMode); static void Enet_MTL_SetRxQueueMap0(ENET_HandleType *pEnetHandle); static void Enet_MTLInit(ENET_HandleType *pEnetHandle, const ENET_MTLConfigType *pMTLConfig); #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) static void Enet_ReleaseRxDescBuffers(ENET_HandleType *pEnetHandle); #endif static void Enet_DMATxDescInit(ENET_HandleType *pEnetHandle, const ENET_DescConfigType pTxDesc[], bool bEnhancedDesc); static inline void Enet_SetupRxDesc(ENET_HandleType *pEnetHandle, ENET_DMADescType *pDesc); static void Enet_DMARxDescInit(ENET_HandleType *pEnetHandle, const ENET_DescConfigType pRxDesc[]); static bool Enet_ReadTxDescTimestamp(ENET_HandleType *pEnetHandle, const ENET_DMADescPtrType DescPtr, ENET_DescModeType DesMode, ENET_TimestampType *pTimestamp); static ENET_StatusType Enet_Stop_Process(ENET_HandleType *pEnetHandle); static void Enet_ReadRxDescTimestamp(ENET_HandleType *pEnetHandle, const ENET_DMADescType *pDesc, ENET_TimestampType *pTimestamp); static inline ENET_DMADescType *Enet_NextDescriptor(ENET_DMADescType *pCurDesc, ENET_DescListType *pDescList); static ENET_DMADescPtrType Enet_NextTxDescriptor(ENET_DMADescPtrType pCurDesc, ENET_DescListType *pDescList); static ENET_StatusType Enet_SetupTxContextDesc(ENET_HandleType *pEnetHandle, ENET_DMADescType *pDesc, ENET_TxOptionType *pOption, uint32_t *pContextDesc); static ENET_StatusType Enet_BuildTxDescriptors(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_BufferType *pBuffers, ENET_TxOptionType *pOption); static void Enet_ReleaseRxDescriptors(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_DMADescType *pStart, ENET_DMADescType *pEnd); static ENET_StatusType Enet_GetRxBuffers(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_BufferType *pBuffers, ENET_RxInfoType *pInfo); static ENET_StatusType Enet_MDIOWriteAddress(ENET_Type *pBase, bool bClause45, ENET_MiiOptType u8Opt, uint8_t u8PhyAddr, uint16_t u16PhyReg, uint8_t u8MmdAddr, uint16_t *pData, uint32_t u32TimeoutUs); static void Enet_MacAddressConfig(ENET_Type *EnetBase, const uint8_t *pMacAddr, uint8_t u8MacLen); static uint32_t Enet_ComputeCRC(const uint8_t *pData, uint32_t u32BitLen); static inline uint32_t Enet_BitsReverse(uint32_t u32Data); static inline void Enet_MACFilterConfig(ENET_Type *EnetBase, const ENET_MACFilterType *pMACFilter); static ENET_StatusType Enet_VlanCtrlBusyPollWait(const ENET_Type *pEnetBase, uint32_t u32TryTimes); static ENET_StatusType Enet_VlanInclBusyPollWait(const ENET_Type *pEnetBase, uint32_t u32TryTimes); static ENET_StatusType Enet_VlanInclWrite(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_MAC_VLANType eVlanType, uint16_t u16VlanTag); static inline uint32_t Enet_PTPClockSourceConfig(ENET_Type *const pEnet, const Enet_PTPConfigType *pPTPConfig); static ENET_StatusType Enet_CheckPTPClockStepValid(const Enet_PTPConfigType *pPTPConfig, uint32_t u32ClkFreq); static inline uint32_t Enet_PTPRegValue2Nanoseconds(uint32_t u32Subseconds); static inline uint32_t Enet_PTPNanoseconds2RegValue(uint32_t u32Nanoseconds); static void Enet_PTPSetIncrementValue(ENET_HandleType *pEnetHandle, const Enet_PTPConfigType *pPTPConfig, uint32_t PtpClkFreq); static ENET_StatusType Enet_PTPCtrlPollWait(const ENET_Type *pEnetBase, uint32_t u32PollMask, uint32_t u32Timeout); static inline ENET_StatusType Enet_PTPInitializeSystemTime(ENET_HandleType *pEnetHandle, ENET_MAC_TimestampRolloverType eRolloverMode, const ENET_TimestampType *pTime); static void Enet_PTPSetIngressSyncCorrection(ENET_HandleType *pEnetHandle, ENET_MAC_TimestampRolloverType eRolloverMode, uint32_t IngressCorrection); static void Enet_PTPSetEgressSyncCorrection(ENET_HandleType *pEnetHandle, ENET_MAC_TimestampRolloverType eRolloverMode, uint32_t EgressCorrection); static void Enet_CalculatePPSIntervalWidth(ENET_HandleType *pEnetHandle, ENET_MAC_PPSChannelType ePPSChannel, ENET_MAC_TimestampRolloverType eRolloverMode, uint32_t *pInterval, uint32_t *pWidth); static ENET_StatusType Enet_PTPSetTargetTime(ENET_HandleType *pEnetHandle, ENET_MAC_PPSChannelType ePPSChannel, ENET_MAC_TimestampRolloverType eRolloverMode, const ENET_TimestampType *pTime); #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK static ENET_StatusType Enet_GclRead(ENET_HandleType *pEnetHandle, bool bGcrr, uint8_t u8Address, uint32_t *pData); static ENET_StatusType Enet_GclWrite(ENET_HandleType *pEnetHandle, bool bGcrr, uint8_t u8Address, uint32_t u32Data); #endif /* ENET_SUPPORT_TIME_SENSITIVE_NETWORK */ static void Enet_PTPIrqHandler(ENET_HandleType *pEnetHandle); static void Enet_MMCIrqHandler(ENET_HandleType *pEnetHandle); static void Enet_MACIrqHandler(ENET_HandleType *pEnetHandle); static void Enet_MTLIrqHandler(ENET_HandleType *pEnetHandle); static void Enet_DMAIrqHandler(ENET_HandleType *pEnetHandle, uint8_t u8Channel); #if (ENET_DEV_ERROR_REPORT == STD_ON) #define ENET_ReportDevError(func, error) ReportDevError(ENET_MODULE_ID, func, error) static uint32_t Enet_HandleInstanceCheck(const ENET_HandleType *pEnetHandle, uint16_t sid); static uint32_t Enet_AssertMACConfiguration(const ENET_ConfigType *pConfig); static uint32_t Enet_AssertMTLConfiguration(const ENET_ConfigType *pConfig); static uint32_t Enet_AssertDMAConfiguration(const ENET_ConfigType *pConfig); static uint32_t Enet_AssertConfiguration(const ENET_ConfigType *pConfig); static uint32_t Enet_AssertDescBuffer(const ENET_DescConfigType *pTxDesc, uint8_t u8TxChannel, const ENET_DescConfigType *pRxDesc, uint8_t u8RxChannel); static uint32_t Enet_AssertTxBuffer(const ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, const ENET_BufferType *pBuffers); static uint32_t Enet_AssertTxOption(const ENET_HandleType *pEnetHandle, const ENET_TxOptionType *pOption); #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) static uint32_t Enet_AssertRxBuffer(const ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, const ENET_BufferType *pBuffer); #endif static uint32_t Enet_AssertMACFilterConfiguration(const ENET_MACFilterType *pMACFilter); static uint32_t Enet_AssertL3L4FilterConfiguration(ENET_HandleType * pEnetHandle, const ENET_L3L4FilterType *pL3L4Filter); static uint32_t Enet_AssertVlanFilterConfiguration(const ENET_VlanFilterConfigType *pVlanFilterConfig); static uint32_t Enet_AssertVlanPerfectFilterConfiguration(const ENET_VlanPerfectFilterType *pPerfectFilter); static uint32_t Enet_AssertVlanChannelBasedInsConfiguration(ENET_HandleType *pEnetHandle, const ENET_OuterVlanCBTIType *pVlanConfig); static uint32_t Enet_AssertPTPConfiguration(const Enet_PTPConfigType *pPTPConfig); static uint32_t Enet_AssertFlowControlConfiguration(const ENET_HandleType *pEnetHandle, const ENET_FlowControlType *pFlowControl); #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK static uint32_t Enet_AssertEstConfiguration(const ENET_EstConfigType *pEstConfig); static uint32_t Enet_AssertGclConfiguration(const ENET_GateCtrlListType *pGatelist); static uint32_t Enet_AssertPreemptionConfiguration(const ENET_PreemptionConfigType *pConfig); #endif /* ENET_SUPPORT_TIME_SENSITIVE_NETWORK */ /** * @brief : ENET handle and instance number development check * @param[in] pEnetHandle : ENET driver handle * @param[in] sid : The service id of caller * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS No development error * @retval ENET_STATUS_ERROR A development error detected */ static uint32_t Enet_HandleInstanceCheck(const ENET_HandleType *pEnetHandle, uint16_t sid) { uint32_t ret = 1u; if (pEnetHandle == NULL_PTR) { ENET_ReportDevError(sid, ENET_E_PARAM_HANDLE); } else { if (pEnetHandle->eInstance >= ENET_INSTANCE_COUNT) { ENET_ReportDevError(sid, ENET_E_PARAM_INSTANCE); } else { ret = 0u; } } return ret; } /** * @brief : Assert ENET configurations * @param[in] pConfig : ENET configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertMACConfiguration(const ENET_ConfigType *pConfig) { const ENET_MACConfigType *pMACConfig = &pConfig->MACConfig; uint32_t err; err = Enet_AssertMACFilterConfiguration(&pMACConfig->MACFilter); err |= ((pMACConfig->SrcAddrCtrl != ENET_MAC_SRC_ADDR_CTRL_BY_INPUT_SIGNAL) && (pMACConfig->SrcAddrCtrl != ENET_MAC_SRC_ADDR_INSERT_BY_MAC_ADDR_IDX_0) && (pMACConfig->SrcAddrCtrl != ENET_MAC_SRC_ADDR_REPLACE_BY_MAC_ADDR_IDX_0) && (pMACConfig->SrcAddrCtrl != ENET_MAC_SRC_ADDR_INSERT_BY_MAC_ADDR_IDX_1) && (pMACConfig->SrcAddrCtrl != ENET_MAC_SRC_ADDR_REPLACE_BY_MAC_ADDR_IDX_1)) ? 1u : 0u; err |= ((uint32_t)pMACConfig->InterPacketGap > (uint32_t)ENET_MAC_INTER_PACKET_GAP_40_BIT) ? 1u : 0u; err |= ((uint32_t)pMACConfig->BackOffLimit > (uint32_t)ENET_MAC_BACK_OFF_LIMIT_1_SLOT) ? 1u : 0u; err |= ((uint32_t)pMACConfig->ExtInterPktGap > (uint32_t)ENET_MAC_EXT_INTER_PACKET_GAP_352_BIT) ? 1u : 0u; err |= ((uint32_t)pMACConfig->GiantPktSizeLimit > 0x3FFFu) ? 1u : 0u; err |= ((uint32_t)pMACConfig->WatchdogTimeout > (uint32_t)ENET_MAC_WDG_TIMER_SIZE_15KB) ? 1u : 0u; return err; } /** * @brief : Assert ENET configurations * @param[in] pConfig : ENET configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertMTLConfiguration(const ENET_ConfigType *pConfig) { const ENET_MTLQueueConfigType *pMtlQueueCfg; uint8_t u8Channel; uint32_t err; uint32_t u32TotalSize; err = ((pConfig->MTLConfig.TxSchedAlgo != ENET_MTL_SCHED_ALGO_WRR) && (pConfig->MTLConfig.TxSchedAlgo != ENET_MTL_SCHED_ALGO_SP)) ? 1u : 0u; err |= ((uint32_t)pConfig->MTLConfig.RxArbitrationAlgo > (uint32_t)ENET_MTL_RX_ARBITRATION_WEIGHTED_STRICT_POLICY) ? 1u : 0u; /* Transmit queue */ u32TotalSize = 0u; for (u8Channel = 0u; u8Channel < pConfig->TxChannelCount; ++u8Channel) { pMtlQueueCfg = &(pConfig->MTLConfig.QueueConfigs[u8Channel]); err |= ((pMtlQueueCfg->TxFifoSize % 256u) != 0u) ? 1u : 0u; u32TotalSize += pMtlQueueCfg->TxFifoSize; err |= (uint32_t)((uint32_t)pMtlQueueCfg->TxQueueEnable > (uint32_t)ENET_MTL_QUEUE_ENABLE_GENERIC); err |= (uint32_t)(((uint32_t)pMtlQueueCfg->TxThreshold > (uint32_t)ENET_MTL_TX_THRESHOLD_256B) && (pMtlQueueCfg->TxThreshold != ENET_MTL_TX_STORE_FORWARD)); if ((pMtlQueueCfg->TxQueueEnable == ENET_MTL_QUEUE_ENABLE_GENERIC) && (pConfig->MTLConfig.TxSchedAlgo == ENET_MTL_SCHED_ALGO_WRR)) { err |= ((pMtlQueueCfg->IdleSlopeQuantumWeight == 0u) || (pMtlQueueCfg->IdleSlopeQuantumWeight > 0x64u)) ? 1u : 0u; } if (pMtlQueueCfg->TxQueueEnable == ENET_MTL_QUEUE_ENABLE_AV_MODE) { if (pConfig->Speed == ENET_MAC_SPEED_1000MBPS) { err |= (pMtlQueueCfg->IdleSlopeQuantumWeight > 0x2000u) ? 1u : 0u; err |= (pMtlQueueCfg->SendSlopeCredit > 0x2000u) ? 1u : 0u; } else if (pConfig->Speed == ENET_MAC_SPEED_100MBPS) { err |= (pMtlQueueCfg->IdleSlopeQuantumWeight > 0x1000u) ? 1u : 0u; err |= (pMtlQueueCfg->SendSlopeCredit > 0x1000u) ? 1u : 0u; } else { err |= 1u; } err |= (pMtlQueueCfg->HiCredit > 0x8000000u) ? 1u : 0u; err |= (pMtlQueueCfg->LoCredit > 0x8000000u) ? 1u : 0u; err |= (pConfig->Duplex == ENET_MAC_HALF_DUPLEX) ? 1u : 0u; err |= pMtlQueueCfg->RxHwFlowCtrlEnable ? 1u : 0u; } } err |= (u32TotalSize > ENET_MTL_TX_FIFO_SIZE) ? 1u : 0u; /* Receive queue */ u32TotalSize = 0u; for (u8Channel = 0u; u8Channel < pConfig->RxChannelCount; ++u8Channel) { pMtlQueueCfg = &(pConfig->MTLConfig.QueueConfigs[u8Channel]); err |= ((pMtlQueueCfg->RxFifoSize % 256u) != 0u) ? 1u : 0u; u32TotalSize += pMtlQueueCfg->RxFifoSize; err |= ((uint32_t)pMtlQueueCfg->RxDeactiveThreshold > (uint32_t)ENET_MTL_RX_FLOWCTRL_THRESHOLD_FULL_8_5_KB) ? 1u : 0u; err |= ((uint32_t)pMtlQueueCfg->RxActiveThreshold > (uint32_t)ENET_MTL_RX_FLOWCTRL_THRESHOLD_FULL_8_5_KB) ? 1u : 0u; err |= (((uint32_t)pMtlQueueCfg->RxThreshold > ENET_MTL_RX_THRESHOLD_128B) && (pMtlQueueCfg->RxThreshold != ENET_MTL_RX_STORE_FORWARD)) ? 1u : 0u; err |= ((uint32_t)pMtlQueueCfg->RxQueueWeight >= (uint32_t)(1u << ENET_MTL_RXQn_CONTROL_RXQ_WEGT_WIDTH)) ? 1u : 0u; err |= ((pMtlQueueCfg->RxQueueEnable != ENET_MTL_QUEUE_DISABLE) && (pMtlQueueCfg->RxQueueEnable != ENET_MTL_QUEUE_ENABLE_GENERIC)) ? 1u : 0u; } err |= (u32TotalSize > ENET_MTL_RX_FIFO_SIZE) ? 1u : 0u; return err; } /** * @brief : Assert ENET configurations * @param[in] pConfig : ENET configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertDMAConfiguration(const ENET_ConfigType *pConfig) { const ENET_DMAChannelConfigType *pDMAChannelCfg; uint8_t u8Channel; uint32_t err; err = ((pConfig->DMAConfig.PriorityMode != ENET_DMA_PRIORITY_MODE_RX_TX) && (pConfig->DMAConfig.PriorityMode != ENET_DMA_PRIORITY_MODE_TX_RX)) ? 1u : 0u; err |= ((uint32_t)pConfig->DMAConfig.PriorityRatio > (uint32_t)ENET_DMA_PRIORITY_RATIO_8_1) ? 1u : 0u; err |= ((uint32_t)pConfig->DMAConfig.TxArbitration > (uint32_t)ENET_DMA_TX_ARBITRATION_ALGORITHM_WEIGHTED_ROUND_ROBIN) ? 1u : 0u; err |= ((uint32_t)pConfig->DMAConfig.TxRxArbitration > (uint32_t)ENET_DMA_TXRX_ARBITRATION_SCHEME_FIXED_PRIORITY) ? 1u : 0u; err |= ((pConfig->DMAConfig.BurstMode != ENET_BURSTLENGTH_FIXED) && (pConfig->DMAConfig.BurstMode != ENET_BURSTLENGTH_MIXED)) ? 1u : 0u; for (u8Channel = 0u; u8Channel < pConfig->TxChannelCount; ++u8Channel) { pDMAChannelCfg = &(pConfig->DMAConfig.ChannelConfigs[u8Channel]); err |= ((pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_1_BEAT) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_2_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_4_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_8_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_16_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_32_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_64_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_128_BEATS) && (pDMAChannelCfg->BurstLength != ENET_DMA_BURST_LENGTH_256_BEATS)) ? 1u : 0u; err |= ((uint32_t)pDMAChannelCfg->TxChannelWeight >= (uint32_t)(1u << ENET_DMA_CHn_TX_CONTROL_TCW_WIDTH)) ? 1u : 0u; } return err; } /** * @brief : Assert ENET configurations * @param[in] pConfig : ENET configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertConfiguration(const ENET_ConfigType *pConfig) { uint32_t err = 0u; err |= (pConfig->RxChannelCount > ENET_CHANNEL_COUNT) ? 1u : 0u; err |= (pConfig->TxChannelCount > ENET_CHANNEL_COUNT) ? 1u : 0u; err |= ((uint32_t)pConfig->RxIntMode > (uint32_t)ENET_POLLING_MODE) ? 1u : 0u; err |= ((uint32_t)pConfig->TxIntMode > (uint32_t)ENET_BACK2BACK_MODE) ? 1u : 0u; /* Assert buffers configuration */ err |= Enet_AssertDescBuffer(pConfig->TxBD, pConfig->TxChannelCount, pConfig->RxBD, pConfig->RxChannelCount); err |= ((pConfig->MiiMode != ENET_MAC_PHY_MII) #if ENET_SUPPORT_RMII && (pConfig->MiiMode != ENET_MAC_PHY_RMII) #endif #if ENET_SUPPORT_RGMII && (pConfig->MiiMode != ENET_MAC_PHY_RGMII) #endif ) ? 1u : 0u; #if ENET_SUPPORT_RGMII err |= ((pConfig->MiiMode == ENET_MAC_PHY_RGMII) && (pConfig->RgmiiClk != ENET_MAC_RGMII_CLK_SEL_ENET_REF_CLK) && (pConfig->RgmiiClk != ENET_MAC_RGMII_CLK_SEL_PLL0DIVH) && (pConfig->RgmiiClk != ENET_MAC_RGMII_CLK_SEL_PLL1DIVH)) ? 1u : 0u; #endif err |= (uint32_t)((pConfig->Speed != ENET_MAC_SPEED_100MBPS) && #if ENET_SUPPORT_1000MBPS (pConfig->Speed != ENET_MAC_SPEED_1000MBPS) && #endif (pConfig->Speed != ENET_MAC_SPEED_10MBPS)) ? 1u : 0u; err |= ((pConfig->Duplex != ENET_MAC_FULL_DUPLEX) && (pConfig->Duplex != ENET_MAC_HALF_DUPLEX)) ? 1u : 0u; /* Assert Mii configuration */ err |= ((uint32_t)pConfig->MiiConfig.TrailingClocks > (1u << ENET_MAC_MDIO_ADDRESS_NTC_WIDTH)) ? 1u : 0u; err |= ((pConfig->MiiConfig.TrailingClocks == 0u) && (pConfig->MiiConfig.BackToBack == true)) ? 1u : 0u; err |= Enet_AssertMACConfiguration(pConfig); err |= Enet_AssertMTLConfiguration(pConfig); err |= Enet_AssertDMAConfiguration(pConfig); return (ENET_StatusType)err; } /** * @brief Assert the ENET DMA descriptors parameters * @param[in] pTxDesc TX descriptors configure structure * @param[in] u8TxChannel The number of DMA TX channels to use * @param[in] pRxDesc RX descriptors configure structure * @param[in] u8RxChannel The number of DMA RX channels to use * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertDescBuffer(const ENET_DescConfigType *pTxDesc, uint8_t u8TxChannel, const ENET_DescConfigType *pRxDesc, uint8_t u8RxChannel) { uint8_t u8Channel; uint32_t err = 0u; const ENET_DescConfigType *pDescCfg; const ENET_BufferType *pBuf; uint16_t i; for (u8Channel = 0u; u8Channel < u8TxChannel; ++u8Channel) { pDescCfg = &pTxDesc[u8Channel]; if ((pDescCfg->DescList == NULL_PTR) || (!ENET_CHECK_ADDR_IN_SRAM(pDescCfg->DescList)) || (pDescCfg->RingSize < 4u) || (pDescCfg->BufferLen > ENET_MAX_FRAME_LENGTH)) { err = 1u; break; } } for (u8Channel = 0u; u8Channel < u8RxChannel; ++u8Channel) { pDescCfg = &pRxDesc[u8Channel]; if ((pDescCfg->DescList == NULL_PTR) || (!ENET_CHECK_ADDR_IN_SRAM(pDescCfg->DescList)) || (pDescCfg->Buffers == NULL_PTR) || (pDescCfg->RingSize <= 2u) || ((pDescCfg->BufferLen % 2u) != 0u)) { err = 1u; break; } if (pDescCfg->CacheWriteBack) { for (i = 0u; i < pDescCfg->RingSize; ++i) { pBuf = &pDescCfg->Buffers[i]; if (ENET_CACHE_ADDR_UNALIGNED(pBuf->Data) || ENET_CACHE_ADDR_UNALIGNED(pBuf->Data + pBuf->Length)) { err = 1u; break; } } } } return err; } /** * @brief Assert the ENET transmit buffers valid * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel The ENET TX channel ID * @param[in] pBuffers Transmit buffers * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertTxBuffer(const ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, const ENET_BufferType *pBuffers) { uint32_t err = 0u; const ENET_BufferType *pBuf = pBuffers; const ENET_DescListType *pDescList = &pEnetHandle->TxDescLists[eChannel]; while (pBuf != NULL_PTR) { if ((pBuf->Data == NULL_PTR) || ((!ENET_CHECK_ADDR_IN_SRAM(pBuf->Data)) && (!ENET_CHECK_ADDR_IN_DTCM(pBuf->Data))) || (pBuf->Length == 0u) || (pBuf->Length > pDescList->BufferLen)) { err = 1u; break; } pBuf = pBuf->Next; } return err; } /** * @brief Assert the ENET transmit option parameters * @param[in] pEnetHandle ENET driver handle * @param[in] pOption Transmit option parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertTxOption(const ENET_HandleType *pEnetHandle, const ENET_TxOptionType *pOption) { uint32_t err = 0u; if (pOption != NULL_PTR) { if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_CRC_PAD_CTRL)) { err |= (pOption->CrcPadCtrl > ENET_CRC_REPLACEMENT) ? 1u : 0u; } if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_CHECKSUM_INSERTION)) { err |= (pOption->CheckSumCtrl > ENET_CHECKSUM_INSERTION_PROTO_PSEUDOH) ? 1u : 0u; #if (0 == ENET_ALL_TXQUEUES_SUPPORT_CHECKSUM) err |= (pEnetHandle->TxChannelCount > 1u) ? 1u : 0u; #else (void)pEnetHandle; #endif } if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_VLAN_TAG_CTRL)) { err |= ((uint32_t)pOption->VlanConfig.VlanCtrl > (uint32_t)ENET_MAC_VLAN_TAG_REPLACEMENT) ? 1u : 0u; err |= ((pOption->VlanConfig.VlanType != ENET_MAC_VLAN_TYPE_C_VLAN) && (pOption->VlanConfig.VlanType != ENET_MAC_VLAN_TYPE_S_VLAN)) ? 1u : 0u; } if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_INNER_VLAN_TAG_CTRL)) { err |= ((uint32_t)pOption->InnerVlanConfig.VlanCtrl > (uint32_t)ENET_MAC_VLAN_TAG_REPLACEMENT) ? 1u : 0u; err |= ((pOption->InnerVlanConfig.VlanType != ENET_MAC_VLAN_TYPE_C_VLAN) && (pOption->InnerVlanConfig.VlanType != ENET_MAC_VLAN_TYPE_S_VLAN)) ? 1u : 0u; } } return err; } #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) /** * @brief Assert the receive buffer parameters * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel ENET channel * @param[in] pBuffer ENET buffer for building RX descriptors * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertRxBuffer(const ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, const ENET_BufferType *pBuffer) { uint32_t err = 0u; const ENET_DescListType *pDescList = &pEnetHandle->RxDescLists[eChannel]; const ENET_BufferType *pBuf; if (pBuffer != NULL_PTR) { pBuf = pBuffer; while (pBuf != NULL_PTR) { if ((pBuf->Ustate == NULL_PTR) || (pBuf->Data == NULL_PTR) || (((uint32_t)pBuf->Data & 1u) != 0u) || ((!ENET_CHECK_ADDR_IN_SRAM(pBuf->Data)) && (!ENET_CHECK_ADDR_IN_DTCM(pBuf->Data))) || (pBuf->Length < pDescList->BufferLen) || (pDescList->WriteBack && (ENET_CACHE_ADDR_UNALIGNED(pBuf->Data) || ENET_CACHE_ADDR_UNALIGNED(pBuf->Data + pBuf->Length)))) { err = 1u; break; } pBuf = pBuf->Next; } } else { err = 1u; } return err; } #endif /** * @brief Assert MAC filter configurations * @param[in] pMACFilter MAC filter Configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertMACFilterConfiguration(const ENET_MACFilterType *pMACFilter) { uint32_t err; err = ((uint32_t)pMACFilter->PassCtrlPkts > (uint32_t)ENET_MAC_CTRL_PACKET_ADDR_FILTER) ? 1u : 0u; err |= ((uint32_t)pMACFilter->SAFilter > (uint32_t)ENET_FILTER_INVERSE_ENABLE) ? 1u : 0u; err |= ((uint32_t)pMACFilter->DAFilter > (uint32_t)ENET_FILTER_INVERSE_ENABLE) ? 1u : 0u; return err; } /** * @brief Assert layer3 layer4 filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pL3L4Filter Layer3 layer4 filter configurations * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertL3L4FilterConfiguration(ENET_HandleType * pEnetHandle, const ENET_L3L4FilterType *pL3L4Filter) { uint32_t err = 0u; if (pL3L4Filter->DMAChannelSelect) { err |= (pL3L4Filter->DMAChannel >= pEnetHandle->RxChannelCount) ? 1u : 0u; } err |= ((pL3L4Filter->L4Protocol != ENET_MAC_LAYER_4_PROTOCOL_TCP) && (pL3L4Filter->L4Protocol != ENET_MAC_LAYER_4_PROTOCOL_UDP)) ? 1u : 0u; err |= ((uint32_t)pL3L4Filter->DstPortFilter > (uint32_t)ENET_FILTER_INVERSE_ENABLE) ? 1u : 0u; err |= ((uint32_t)pL3L4Filter->SrcPortFilter > (uint32_t)ENET_FILTER_INVERSE_ENABLE) ? 1u : 0u; err |= ((pL3L4Filter->L3Protocol != ENET_MAC_LAYER_3_PROTOCOL_IPV4) && (pL3L4Filter->L3Protocol != ENET_MAC_LAYER_3_PROTOCOL_IPV6)) ? 1u : 0u; err |= ((uint32_t)pL3L4Filter->DstIPFilter > (uint32_t)ENET_FILTER_INVERSE_ENABLE) ? 1u : 0u; err |= ((uint32_t)pL3L4Filter->SrcIPFilter > (uint32_t)ENET_FILTER_INVERSE_ENABLE) ? 1u : 0u; if (pL3L4Filter->L3Protocol == ENET_MAC_LAYER_3_PROTOCOL_IPV4) { err |= (pL3L4Filter->Ipv4DAMaskBit > 31u) ? 1u : 0u; err |= (pL3L4Filter->Ipv4SAMaskBit > 31u) ? 1u : 0u; } else { err |= (pL3L4Filter->Ipv6MaskBit > 127u) ? 1u : 0u; } return err; } /** * @brief Assert MAC VLAN filter configurations * @param[in] pVlanFilterConfig MAC VLAN filter configurations * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertVlanFilterConfiguration(const ENET_VlanFilterConfigType *pVlanFilterConfig) { uint32_t err = 0u; err |= ((uint32_t)pVlanFilterConfig->InnerVlanStrip > (uint32_t)ENET_MAC_VLAN_TAG_STRIP_ALWAYS) ? 1u : 0u; err |= ((uint32_t)pVlanFilterConfig->OuterVlanStrip > (uint32_t)ENET_MAC_VLAN_TAG_STRIP_ALWAYS) ? 1u : 0u; err |= ((uint32_t)pVlanFilterConfig->HashFilterMode > (uint32_t)ENET_VLAN_FILTER_INNER_ANYTYPE) ? 1u : 0u; err |= ((pVlanFilterConfig->HashCompareMode != ENET_MAC_VLAN_16BITS_COMPARE) && (pVlanFilterConfig->HashCompareMode != ENET_MAC_VLAN_12BITS_COMPARE)) ? 1u : 0u; return err; } /** * @brief Assert VLAN perfect filter configurations * @param[in] pPerfectFilter VLAN perfect filter configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertVlanPerfectFilterConfiguration(const ENET_VlanPerfectFilterType *pPerfectFilter) { uint32_t err = 0u; err |= (((uint32_t)pPerfectFilter->DMAChannel > (uint32_t)ENET_CHANNEL_1)) ? 1u : 0u; err |= ((uint32_t)pPerfectFilter->FilterMode > (uint32_t)ENET_VLAN_FILTER_INNER_ANYTYPE) ? 1u : 0u; return err; } /** * @brief Assert VLAN perfect filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pVlanConfig VLAN perfect filter configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertVlanChannelBasedInsConfiguration(ENET_HandleType *pEnetHandle, const ENET_OuterVlanCBTIType *pVlanConfig) { uint8_t u8Channel; uint32_t err = 0u; if (pVlanConfig->Enable) { for (u8Channel = 0u; u8Channel < pEnetHandle->TxChannelCount; ++u8Channel) { if ((pVlanConfig->VlanType[u8Channel] != ENET_MAC_VLAN_TYPE_C_VLAN) && (pVlanConfig->VlanType[u8Channel] != ENET_MAC_VLAN_TYPE_S_VLAN)) { err = 1u; break; } } } return err; } /** * @brief Assert the PTP configure parameters * @param[in] pPTPConfig PTP default configurations * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertPTPConfiguration(const Enet_PTPConfigType *pPTPConfig) { uint32_t err = 0u; err |= ((pPTPConfig->TXTSSTSM != ENET_MAC_TX_TIMESTAMP_STATUS_MODE_PRESERVE) && (pPTPConfig->TXTSSTSM != ENET_MAC_TX_TIMESTAMP_STATUS_MODE_OVERWRITE)) ? 1u : 0u; err |= ((pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_E2E) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_SYNC) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_DELAYREQ) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_ALL_PTP) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_SLAVE_NODE_EVENT) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_MASTER_NODE_EVENT) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_E2E_EVENT) && (pPTPConfig->SnapshotType != ENET_MAC_PTP_SNAPSHOT_FOR_P2P_EVENT)) ? 1u : 0u; err |= ((pPTPConfig->PtpLayer != ENET_MAC_PTP_OVER_ETHERNET) && (pPTPConfig->PtpLayer != ENET_MAC_PTP_OVER_IPV4) && (pPTPConfig->PtpLayer != ENET_MAC_PTP_OVER_IPV6)) ? 1u : 0u; err |= ((pPTPConfig->PtpVersion != ENET_MAC_PTP_IEEE_1588_V1) && (pPTPConfig->PtpVersion != ENET_MAC_PTP_IEEE_1588_V2)) ? 1u : 0u; err |= ((pPTPConfig->RolloverMode != ENET_MAC_TIMESTAMP_ROLLOVER_BINARY) && (pPTPConfig->RolloverMode != ENET_MAC_TIMESTAMP_ROLLOVER_DIGITAL)) ? 1u : 0u; err |= ((pPTPConfig->UpdateMethod != ENET_MAC_TIMESTAMP_UPDATE_COARSE) && (pPTPConfig->UpdateMethod != ENET_MAC_TIMESTAMP_UPDATE_FINE)) ? 1u : 0u; err |= ((pPTPConfig->ClkSource != ENET_MAC_PTP_CLK_SEL_PCC) && (pPTPConfig->ClkSource != ENET_MAC_PTP_CLK_SEL_TX_CLK) #if ENET_SUPPORT_REFCLK_PIN && (pPTPConfig->ClkSource != ENET_MAC_PTP_CLK_SEL_REFCLK_PIN) #endif ) ? 1u : 0u; /* Due to the bug in 5.20a errata, the MAC unable to identify PTP SYNC and Follow_Up Messages with Peer Delay Reserved Multicast Address in the 802.1AS Mixed Mode, therefore, enable timestamp for all packets(MAC_TIMESTAMP_CONTROL[8]) must be enabled. */ if ((pPTPConfig->Av8021ASMode == true) && (pPTPConfig->TimeStampForAll == false)) { err = 1u; } return err; } /** * @brief Assert flow control configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pFlowControl MAC flow control Configure parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertFlowControlConfiguration(const ENET_HandleType *pEnetHandle, const ENET_FlowControlType *pFlowControl) { const ENET_FlowControlRxQType *pFlowCtrlRxQCfg; uint32_t u8Channel; uint32_t err = 0u; err |= ((uint32_t)pFlowControl->PauseThreshold > (uint32_t)ENET_MAC_PAUSE_THRESHOLD_512SLOT_TIMES) ? 1u : 0u; for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { pFlowCtrlRxQCfg = &(pFlowControl->RxQueueConfig[u8Channel]); err |= ((uint32_t)pFlowCtrlRxQCfg->RxDeactiveThreshold > (uint32_t)ENET_MTL_RX_FLOWCTRL_THRESHOLD_FULL_8_5_KB) ? 1u : 0u; err |= ((uint32_t)pFlowCtrlRxQCfg->RxActiveThreshold > (uint32_t)ENET_MTL_RX_FLOWCTRL_THRESHOLD_FULL_8_5_KB) ? 1u : 0u; } return (ENET_StatusType)err; } #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK /** * @brief Assert Enhancements to Scheduled Traffic configurations * @param[in] pEstConfig Enhancements to Scheduled Traffic Configuration parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertEstConfiguration(const ENET_EstConfigType *pEstConfig) { uint32_t err = 0u; err |= ((uint32_t)pEstConfig->CurrentTimeOffset > (uint32_t)4096u) ? 1u : 0u; err |= ((uint32_t)pEstConfig->IntervalLeftShift > (uint32_t)ENET_MTL_GCL_INTERVAL_X_128) ? 1u : 0u; err |= ((uint32_t)pEstConfig->SchedErrLoopCount > (uint32_t)ENET_MTL_GCL_32_ITERATIONS) ? 1u : 0u; err |= ((uint32_t)pEstConfig->Overhead > (uint32_t)64u) ? 1u : 0u; /* Due to the bug in 5.20a errata, the HLBS or HLBF may be detected incorrectly, and the packets may be dropped, therefore, DropSchedErrFrame must be false, NotDropFrameSizeErr must be true. */ if ((pEstConfig->DropSchedErrFrame == true) || (pEstConfig->NotDropFrameSizeErr == false)) { err = 1u; } return err; } /** * @brief Assert Gate control list configurations * @param[in] pGatelist Gate control list Configuration parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertGclConfiguration(const ENET_GateCtrlListType *pGatelist) { uint32_t err = 0u; uint32_t i; if (pGatelist->GclLength > ENET_TSN_GCL_DEPTH) { err = 1u; } else { for (i = 0u; i < pGatelist->GclLength; ++i) { if (pGatelist->Gate[i].TimeInterval >= (1u << ENET_TSN_GCL_INTERVAL_WIDTH_BITS)) { err = 1u; break; } } } return err; } /** * @brief Assert Preemption configurations * @param[in] pConfig Preemption Configuration parameters * @return uint32_t * @retval 0 No error in parameters * @retval None-zero An error is detected in parameters */ static uint32_t Enet_AssertPreemptionConfiguration(const ENET_PreemptionConfigType *pConfig) { uint32_t err = 0u; uint32_t i; if (pConfig->PreemptionEnable) { for (i = 0u; i < ENET_CHANNEL_COUNT; ++i) { if ((uint32_t)pConfig->Classification[i] > (uint32_t)ENET_CLISSIFICATION_PREEMPTABLE) { err = 1u; break; } } } return err; } #endif /* ENET_SUPPORT_TIME_SENSITIVE_NETWORK */ #endif /* ENET_DEV_ERROR_REPORT */ /** * @brief Ethernet system control configuration. * @details Set the system control in the system module. * @param[in] pConfig ENET configuration parameters */ static void Enet_SystemConfig(const ENET_ConfigType *pConfig) { ENET_HWA_Sysctrl_SetPhyMiiMode(pConfig->MiiMode); #if ENET_SUPPORT_RGMII if (pConfig->MiiMode == ENET_MAC_PHY_RGMII) { ENET_HWA_Sysctrl_SetRGMIIClockSrc(pConfig->RgmiiClk); ENET_HWA_Sysctrl_SetTxClockSrc(ENET_MAC_TX_CLK_SEL_ENET_TX_CLK); ENET_HWA_Sysctrl_SetMiiTxClkOutputEnFlag(ENET_TRUE); } #endif } /** * @brief Ethernet controller soft reset. * @details Reset the logic and all internal registers of the DMA, MTL, and MAC. * @param[in] pEnetBase ENET controller register base address * @param[in] u32Timeout CPU ticks to wait timeout * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS The reset operation is complete * @retval ENET_STATUS_TIMEOUT The reset operation is failed */ static ENET_StatusType Enet_SoftwareReset(ENET_Type *pEnetBase, uint32_t u32Timeout) { ENET_HWA_DMA_SwReset(pEnetBase); while ((ENET_HWA_DMA_GetSwResetStatus(pEnetBase) != ENET_DMA_STATUS_IDLE) && (u32Timeout > 0u)) { --u32Timeout; } return (u32Timeout == 0u) ? ENET_STATUS_TIMEOUT : ENET_STATUS_SUCCESS; } /** * @brief Initializes the ENET DMA * @param[in] pEnetHandle ENET driver handle * @param[in] pDmaConfig ENET DMA configuration structure */ static void Enet_DMAInit(ENET_HandleType *pEnetHandle, const ENET_DMAConfigType *pDmaConfig) { uint8_t u8Channel, u8SkipLen, u8RingCount, u8BurstLength; ENET_HWA_DMA_SetInterruptMode(pEnetHandle->EnetBase, ENET_DMA_INTM_SBD_PERCH_LEVEL); ENET_HWA_DMA_SetPriorityMode(pEnetHandle->EnetBase, pDmaConfig->PriorityMode); ENET_HWA_DMA_SetPriorityRatio(pEnetHandle->EnetBase, pDmaConfig->PriorityRatio); ENET_HWA_DMA_SetTxArbitrationAlgorithm(pEnetHandle->EnetBase, pDmaConfig->TxArbitration); ENET_HWA_DMA_SetTxRxArbitrationScheme(pEnetHandle->EnetBase, pDmaConfig->TxRxArbitration); ENET_HWA_DMA_SetRebuildINCRxBurstEnFlag(pEnetHandle->EnetBase, pDmaConfig->RebuildINCRxBurst); ENET_HWA_DMA_SetAddressAlignedBeatsEnFlag(pEnetHandle->EnetBase, pDmaConfig->AddressAlignedBeats); if (pDmaConfig->BurstMode == ENET_BURSTLENGTH_FIXED) { ENET_HWA_DMA_SetFixedBurstLengthEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } else { ENET_HWA_DMA_SetMixedBurstEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } u8SkipLen = (uint8_t)(sizeof(ENET_DMADescType) - ENET_DMA_DESC_LEN_BYTES) / ENET_DATA_BUS_WIDTH_BYTES; u8RingCount = (pEnetHandle->TxChannelCount >= pEnetHandle->RxChannelCount) ? pEnetHandle->TxChannelCount : pEnetHandle->RxChannelCount; for (u8Channel = 0; u8Channel < u8RingCount; ++u8Channel) { ENET_HWA_DMA_SetDescriptorSkipLength(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, u8SkipLen); ENET_HWA_DMA_SetEnabledInterrupts(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, 0u); if ((uint32_t)pDmaConfig->ChannelConfigs[u8Channel].BurstLength > 32u) { u8BurstLength = (uint8_t)((uint32_t)pDmaConfig->ChannelConfigs[u8Channel].BurstLength / 8u); ENET_HWA_DMA_Set8xPBLModeEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_TRUE); } else { u8BurstLength = (uint8_t)pDmaConfig->ChannelConfigs[u8Channel].BurstLength; ENET_HWA_DMA_Set8xPBLModeEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_FALSE); } if (u8Channel < pEnetHandle->TxChannelCount) { ENET_HWA_DMA_SetEarlyTxIntEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, pDmaConfig->ChannelConfigs[u8Channel].EarlySendIntEnable); ENET_HWA_DMA_SetTxBurstLength(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, u8BurstLength); ENET_HWA_DMA_SetOperateOnSecondPacketEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, pDmaConfig->ChannelConfigs[u8Channel].OperateSecondPacket); ENET_HWA_DMA_SetTxChannelWeight(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, pDmaConfig->ChannelConfigs[u8Channel].TxChannelWeight); ENET_HWA_DMA_SetEnhancedDescriptorEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, pDmaConfig->EnhancedDescriptor); } if (u8Channel < pEnetHandle->RxChannelCount) { ENET_HWA_DMA_SetRxPacketFlushEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_TRUE); ENET_HWA_DMA_SetEarlyRxIntEnFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, pDmaConfig->ChannelConfigs[u8Channel].EarlyReceiveIntEnable); ENET_HWA_DMA_SetRxBurstLength(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, u8BurstLength); } } } /** * @brief Initializes the ENET MAC * @param[in] pEnetHandle ENET driver handle * @param[in] pMACConfig ENET MAC configuration structure * @param[in] eSpeed ENET MAC connection speed * @param[in] eDuplexMode ENET MAC connection duplex mode */ static void Enet_MACInit(ENET_HandleType *pEnetHandle, const ENET_MACConfigType *pMACConfig, ENET_MAC_SpeedType eSpeed, ENET_MAC_DuplexModeType eDuplexMode) { uint32_t u32RegValue; pEnetHandle->EnetBase->MAC_INTERRUPT_ENABLE = 0u; pEnetHandle->EnetBase->MMC_RX_INTERRUPT_MASK = 0xFFFFFFFFu; pEnetHandle->EnetBase->MMC_TX_INTERRUPT_MASK = 0xFFFFFFFFu; u32RegValue = pEnetHandle->EnetBase->MAC_CONFIGURATION; u32RegValue &= ~(ENET_MAC_CONFIGURATION_SARC_MASK | ENET_MAC_CONFIGURATION_IPC_MASK | ENET_MAC_CONFIGURATION_IPG_MASK | ENET_MAC_CONFIGURATION_GPSLCE_MASK | ENET_MAC_CONFIGURATION_S2KP_MASK | ENET_MAC_CONFIGURATION_CST_MASK | ENET_MAC_CONFIGURATION_ACS_MASK | ENET_MAC_CONFIGURATION_WD_MASK | ENET_MAC_CONFIGURATION_JD_MASK | ENET_MAC_CONFIGURATION_JE_MASK | ENET_MAC_CONFIGURATION_LM_MASK | ENET_MAC_CONFIGURATION_ECRSFD_MASK | ENET_MAC_CONFIGURATION_DO_MASK | ENET_MAC_CONFIGURATION_DCRS_MASK | ENET_MAC_CONFIGURATION_DR_MASK | ENET_MAC_CONFIGURATION_BL_MASK | ENET_MAC_CONFIGURATION_DC_MASK | ENET_MAC_CONFIGURATION_TE_MASK | ENET_MAC_CONFIGURATION_RE_MASK); u32RegValue |= ENET_MAC_CONFIGURATION_SARC(pMACConfig->SrcAddrCtrl) | ENET_MAC_CONFIGURATION_IPC(pMACConfig->ChecksumOffload ? 1u : 0u) | ENET_MAC_CONFIGURATION_IPG(pMACConfig->InterPacketGap) | ENET_MAC_CONFIGURATION_GPSLCE(pMACConfig->GiantPacketLimit ? 1u : 0u) | ENET_MAC_CONFIGURATION_S2KP(pMACConfig->Support2KPacket ? 1u : 0u) | ENET_MAC_CONFIGURATION_CST(pMACConfig->CrcStripForTypePkt ? 1u : 0u) | ENET_MAC_CONFIGURATION_ACS(pMACConfig->AutoPadOrCrCStrip ? 1u : 0u) | ENET_MAC_CONFIGURATION_WD(pMACConfig->WatchDogDisable ? 1u : 0u) | ENET_MAC_CONFIGURATION_JD(pMACConfig->JabberDisable ? 1u : 0u) | ENET_MAC_CONFIGURATION_JE(pMACConfig->JumboEnable ? 1u : 0u) | ENET_MAC_CONFIGURATION_LM(pMACConfig->LoopbackMode ? 1u : 0u) | ENET_MAC_CONFIGURATION_ECRSFD(pMACConfig->CarrierSenseBeforeTx ? 1u : 0u) | ENET_MAC_CONFIGURATION_DO(pMACConfig->DisableReceiveOwn ? 1u : 0u) | ENET_MAC_CONFIGURATION_DCRS(pMACConfig->DisCarrierSenseDurTx ? 1u : 0u) | ENET_MAC_CONFIGURATION_DR(pMACConfig->DisableRetry ? 1u : 0u) | ENET_MAC_CONFIGURATION_BL(pMACConfig->BackOffLimit) | ENET_MAC_CONFIGURATION_DC(pMACConfig->DeferralCheck ? 1u : 0u); pEnetHandle->EnetBase->MAC_CONFIGURATION = u32RegValue; ENET_HWA_MAC_SetSpeed(pEnetHandle->EnetBase, eSpeed); ENET_HWA_MAC_SetDuplexMode(pEnetHandle->EnetBase, eDuplexMode); u32RegValue = pEnetHandle->EnetBase->MAC_EXT_CONFIGURATION; u32RegValue &= ~(ENET_MAC_EXT_CONFIGURATION_EIPG_MASK | ENET_MAC_EXT_CONFIGURATION_EIPGEN_MASK | ENET_MAC_EXT_CONFIGURATION_PDC_MASK | ENET_MAC_EXT_CONFIGURATION_USP_MASK | ENET_MAC_EXT_CONFIGURATION_SPEN_MASK | ENET_MAC_EXT_CONFIGURATION_DCRCC_MASK | ENET_MAC_EXT_CONFIGURATION_GPSL_MASK); u32RegValue |= ENET_MAC_EXT_CONFIGURATION_EIPG(pMACConfig->ExtInterPktGap) | ENET_MAC_EXT_CONFIGURATION_EIPGEN(pMACConfig->ExtInterPktGapEn ? 1u : 0u) | ENET_MAC_EXT_CONFIGURATION_PDC(pMACConfig->PacketDuplication ? 1u : 0u) | ENET_MAC_EXT_CONFIGURATION_USP(pMACConfig->UnicastSlowProtoDetect ? 1u : 0u) | ENET_MAC_EXT_CONFIGURATION_SPEN(pMACConfig->SlowProtoDetectEnable ? 1u : 0u) | ENET_MAC_EXT_CONFIGURATION_DCRCC(pMACConfig->DisableCrcCheck ? 1u : 0u) | ENET_MAC_EXT_CONFIGURATION_GPSL(pMACConfig->GiantPktSizeLimit); pEnetHandle->EnetBase->MAC_EXT_CONFIGURATION = u32RegValue; ENET_HWA_MAC_SetLayer3Layer4FilterEnFlag(pEnetHandle->EnetBase, false); ENET_HWA_MAC_SetVLANTagFilterFilterEnFlag(pEnetHandle->EnetBase, false); Enet_MACFilterConfig(pEnetHandle->EnetBase, &pMACConfig->MACFilter); u32RegValue = pEnetHandle->EnetBase->MAC_WATCHDOG_TIMEOUT; u32RegValue &= ~(ENET_MAC_WATCHDOG_TIMEOUT_PWE_MASK | ENET_MAC_WATCHDOG_TIMEOUT_WTO_MASK); u32RegValue |= ENET_MAC_WATCHDOG_TIMEOUT_PWE(pMACConfig->ProgramWatchdogEnable ? 1u : 0u) | ENET_MAC_WATCHDOG_TIMEOUT_WTO(pMACConfig->WatchdogTimeout); pEnetHandle->EnetBase->MAC_WATCHDOG_TIMEOUT = u32RegValue; } /** * @brief Set up DMA channels and MTL queues map * @param[in] pEnetHandle ENET driver handle */ static void Enet_MTL_SetRxQueueMap0(ENET_HandleType *pEnetHandle) { uint32_t u32RegValue = 0u; #if ENET_CHANNEL_COUNT > 0u u32RegValue |= ENET_MTL_RXQ_DMA_MAP0_Q0DDMACH(0u) | ENET_MTL_RXQ_DMA_MAP0_Q0MDMACH(0u); #endif #if ENET_CHANNEL_COUNT > 1u if (pEnetHandle->RxChannelCount > 1u) { u32RegValue |= ENET_MTL_RXQ_DMA_MAP0_Q1DDMACH(0u) | ENET_MTL_RXQ_DMA_MAP0_Q1MDMACH(1u); } #endif pEnetHandle->EnetBase->MTL.RXQ_DMA_MAP0 = u32RegValue; } /** * @brief Initializes the ENET MTL * @param[in] pEnetHandle ENET driver handle * @param[in] pMTLConfig ENET MTL configuration structure */ static void Enet_MTLInit(ENET_HandleType *pEnetHandle, const ENET_MTLConfigType *pMTLConfig) { const ENET_MTLQueueConfigType *pMtlQueueCfg; uint32_t u32RegValue; uint8_t u8FifoSize; uint8_t u8Channel; for (u8Channel = 0u; u8Channel < pEnetHandle->TxChannelCount; ++u8Channel) { pMtlQueueCfg = &(pMTLConfig->QueueConfigs[u8Channel]); if (ENET_MTL_QUEUE_ENABLE_GENERIC == pMtlQueueCfg->TxQueueEnable) { ENET_HWA_MTL_SetTxQueueQuantumOrWeight(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->IdleSlopeQuantumWeight); } else if ((u8Channel > 0u) && (ENET_MTL_QUEUE_ENABLE_AV_MODE == pMtlQueueCfg->TxQueueEnable)) { /* AV mode */ ENET_HWA_MTL_SetTxQueueQuantumOrWeight(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->IdleSlopeQuantumWeight); ENET_HWA_MTL_SetTxQueueSendSlopeCredit(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->SendSlopeCredit); ENET_HWA_MTL_SetTxQueueHiCredit(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->HiCredit); /* LoCredit is a negative value, the programmed value is 2's complement of the value */ u32RegValue = pMTLConfig->QueueConfigs[u8Channel].LoCredit; ENET_HWA_MTL_SetTxQueueLoCredit(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, (~u32RegValue + 1U)); ENET_HWA_MTL_SetCreditControlEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->CreditControl); ENET_HWA_MTL_SetAVAlgorithmCBSEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, ENET_TRUE); } u8FifoSize = (uint8_t)((pMtlQueueCfg->TxFifoSize / 256u) - 1u); ENET_HWA_MTL_SetTxQueueSize(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, u8FifoSize); ENET_HWA_MTL_SetTxThreshold(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->TxThreshold); ENET_HWA_MTL_SetTxQueueEnStatus(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->TxQueueEnable); } Enet_MTL_SetRxQueueMap0(pEnetHandle); for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { pMtlQueueCfg = &(pMTLConfig->QueueConfigs[u8Channel]); u8FifoSize = (uint8_t)((pMtlQueueCfg->RxFifoSize / 256u) - 1u); ENET_HWA_MTL_SetRxQueueSize(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, u8FifoSize); ENET_HWA_MTL_SetRxDeactivateFlowCtrlThres(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMTLConfig->QueueConfigs[u8Channel].RxDeactiveThreshold); ENET_HWA_MTL_SetRxActivateFlowCtrlThres(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMTLConfig->QueueConfigs[u8Channel].RxActiveThreshold); ENET_HWA_MTL_SetRxHwFlowCtrlEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMTLConfig->QueueConfigs[u8Channel].RxHwFlowCtrlEnable); ENET_HWA_MTL_SetForwardTCPChecksumErrorPacketEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->ReveiveTCPIPCksumErrPkts); ENET_HWA_MTL_SetForwardErrorPacketEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->ReveiveErrorPkts); ENET_HWA_MTL_SetForwardUndersizedPacketEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->ReveiveUndersizeGoodPkts); ENET_HWA_MTL_SetRxThreshold(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->RxThreshold); if (ENET_MTL_RX_ARBITRATION_WEIGHTED_STRICT_POLICY == pMTLConfig->RxArbitrationAlgo) { ENET_HWA_MTL_SetRxQueuePacketArbitrationEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->RxQueueArbitration); ENET_HWA_MTL_SetRxQueueWeight(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMTLConfig->QueueConfigs[u8Channel].RxQueueWeight); } ENET_HWA_MAC_SetRxQueueSelectedPriorities(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pMtlQueueCfg->RxQueuePriority); } ENET_HWA_MTL_SetTxSchedulingAlgorithm(pEnetHandle->EnetBase, pMTLConfig->TxSchedAlgo); ENET_HWA_MTL_SetRxArbitrationAlgorithm(pEnetHandle->EnetBase, pMTLConfig->RxArbitrationAlgo); ENET_HWA_MTL_SetDropTxPacketStatusEnFlag(pEnetHandle->EnetBase, pMTLConfig->EnableTransmitStatus ? false : true); u32RegValue = 0u; for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { u32RegValue |= ((uint32_t)pMTLConfig->QueueConfigs[u8Channel].RxQueueEnable & ENET_MAC_RXQ_CTRL0_RXQ0EN_MASK) << (ENET_MAC_RXQ_CTRL0_RXQ0EN_WIDTH * (uint32_t)u8Channel); } ENET_HWA_MAC_SetRxQueueCtrl0(pEnetHandle->EnetBase, u32RegValue); } /** * @brief Get ENET default configuration * @param[out] pConfig ENET default configurations */ void Enet_DefaultConfig(ENET_ConfigType *pConfig) { uint8_t u8Channel; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (pConfig == NULL_PTR) { ENET_ReportDevError(ENET_DEFAULT_CONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { #endif pConfig->TxChannelCount = ENET_CHANNEL_COUNT; pConfig->RxChannelCount = ENET_CHANNEL_COUNT; pConfig->RxIntMode = ENET_INTERRUPT_MODE; pConfig->TxIntMode = ENET_INTERRUPT_MODE; Enet_MDIODefaultConfig(&pConfig->MiiConfig); #if ENET_SUPPORT_RGMII pConfig->MiiMode = ENET_MAC_PHY_RGMII; pConfig->RgmiiClk = ENET_MAC_RGMII_CLK_SEL_PLL1DIVH; #else pConfig->MiiMode = ENET_MAC_PHY_MII; #endif #if ENET_SUPPORT_1000MBPS pConfig->Speed = ENET_MAC_SPEED_1000MBPS; #else pConfig->Speed = ENET_MAC_SPEED_100MBPS; #endif /* MAC configurations */ pConfig->Duplex = ENET_MAC_FULL_DUPLEX; pConfig->SoftResetTimeout = 3000u; pConfig->SendPollTimeout = 6000u; pConfig->VlanOpTimeout = 1000u; pConfig->PtpCtrlTimeout = 1000u; #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK pConfig->GclOpTimeout = 1000u; #endif for (u8Channel = 0u; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { pConfig->RxBD[u8Channel].CacheWriteBack = ENET_FALSE; pConfig->TxBD[u8Channel].CacheWriteBack = ENET_FALSE; } pConfig->MACConfig.SrcAddrCtrl = ENET_MAC_SRC_ADDR_CTRL_BY_INPUT_SIGNAL; pConfig->MACConfig.ChecksumOffload = ENET_FALSE; pConfig->MACConfig.InterPacketGap = ENET_MAC_INTER_PACKET_GAP_96_BIT; pConfig->MACConfig.GiantPacketLimit = ENET_FALSE; pConfig->MACConfig.Support2KPacket = ENET_FALSE; pConfig->MACConfig.CrcStripForTypePkt = ENET_TRUE; pConfig->MACConfig.AutoPadOrCrCStrip = ENET_TRUE; pConfig->MACConfig.WatchDogDisable = ENET_FALSE; pConfig->MACConfig.JabberDisable = ENET_FALSE; pConfig->MACConfig.JumboEnable = ENET_FALSE; pConfig->MACConfig.LoopbackMode = ENET_FALSE; pConfig->MACConfig.CarrierSenseBeforeTx = ENET_FALSE; pConfig->MACConfig.DisableReceiveOwn = ENET_FALSE; pConfig->MACConfig.DisCarrierSenseDurTx = ENET_FALSE; pConfig->MACConfig.DisableRetry = ENET_FALSE; pConfig->MACConfig.BackOffLimit = ENET_MAC_BACK_OFF_LIMIT_10_SLOT; pConfig->MACConfig.DeferralCheck = ENET_FALSE; pConfig->MACConfig.ExtInterPktGap = ENET_MAC_EXT_INTER_PACKET_GAP_104_BIT; pConfig->MACConfig.ExtInterPktGapEn = ENET_FALSE; pConfig->MACConfig.PacketDuplication = ENET_FALSE; pConfig->MACConfig.UnicastSlowProtoDetect = ENET_FALSE; pConfig->MACConfig.SlowProtoDetectEnable = ENET_FALSE; pConfig->MACConfig.DisableCrcCheck = ENET_FALSE; pConfig->MACConfig.GiantPktSizeLimit = 0u; pConfig->MACConfig.ProgramWatchdogEnable = ENET_FALSE; pConfig->MACConfig.WatchdogTimeout = ENET_MAC_WDG_TIMER_SIZE_2KB; Enet_DefaultMACFilter(&pConfig->MACConfig.MACFilter); /* MTL Transmit and Receive Scheduling Algorithm configurations */ pConfig->MTLConfig.TxSchedAlgo = ENET_MTL_SCHED_ALGO_SP; pConfig->MTLConfig.RxArbitrationAlgo = ENET_MTL_RX_ARBITRATION_WEIGHTED_STRICT_POLICY; pConfig->MTLConfig.EnableTransmitStatus = ENET_TRUE; for (u8Channel = 0u; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { /* MTL Transmit Queues configurations */ pConfig->MTLConfig.QueueConfigs[u8Channel].TxFifoSize = ENET_MTL_TX_FIFO_SIZE / ENET_CHANNEL_COUNT; pConfig->MTLConfig.QueueConfigs[u8Channel].RxFifoSize = ENET_MTL_RX_FIFO_SIZE / ENET_CHANNEL_COUNT; pConfig->MTLConfig.QueueConfigs[u8Channel].TxQueueEnable = ENET_MTL_QUEUE_ENABLE_GENERIC; pConfig->MTLConfig.QueueConfigs[u8Channel].IdleSlopeQuantumWeight = 0u; pConfig->MTLConfig.QueueConfigs[u8Channel].SendSlopeCredit = 0u; pConfig->MTLConfig.QueueConfigs[u8Channel].HiCredit = 0u; pConfig->MTLConfig.QueueConfigs[u8Channel].LoCredit = 0u; pConfig->MTLConfig.QueueConfigs[u8Channel].TxThreshold = ENET_MTL_TX_STORE_FORWARD; /* MTL Receive Queues configurations */ pConfig->MTLConfig.QueueConfigs[u8Channel].RxQueueEnable = ENET_MTL_QUEUE_ENABLE_GENERIC; pConfig->MTLConfig.QueueConfigs[u8Channel].RxThreshold = ENET_MTL_RX_STORE_FORWARD; pConfig->MTLConfig.QueueConfigs[u8Channel].RxDeactiveThreshold = ENET_MTL_RX_FLOWCTRL_THRESHOLD_FULL_1_KB; pConfig->MTLConfig.QueueConfigs[u8Channel].RxActiveThreshold = ENET_MTL_RX_FLOWCTRL_THRESHOLD_FULL_1_KB; pConfig->MTLConfig.QueueConfigs[u8Channel].RxHwFlowCtrlEnable = ENET_FALSE; pConfig->MTLConfig.QueueConfigs[u8Channel].ReveiveTCPIPCksumErrPkts = ENET_FALSE; pConfig->MTLConfig.QueueConfigs[u8Channel].ReveiveErrorPkts = ENET_FALSE; pConfig->MTLConfig.QueueConfigs[u8Channel].ReveiveUndersizeGoodPkts = ENET_FALSE; pConfig->MTLConfig.QueueConfigs[u8Channel].RxQueueArbitration = ENET_TRUE; pConfig->MTLConfig.QueueConfigs[u8Channel].RxQueueWeight = 0u; pConfig->MTLConfig.QueueConfigs[u8Channel].RxQueuePriority = (0xFu << (uint32_t)(u8Channel * 4u)) & 0xFFu; } /* The DMA Arbitration Algorithm between Receive and Transmit Paths */ pConfig->DMAConfig.PriorityMode = ENET_DMA_PRIORITY_MODE_RX_TX; pConfig->DMAConfig.PriorityRatio = ENET_DMA_PRIORITY_RATIO_1_1; pConfig->DMAConfig.TxRxArbitration = ENET_DMA_TXRX_ARBITRATION_SCHEME_WEIGHTED_ROUND_ROBIN; /* The Transmit Arbitration Algorithm for multiple DMA channels */ pConfig->DMAConfig.TxArbitration = ENET_DMA_TX_ARBITRATION_ALGORITHM_WEIGHTED_FIXED_PRIORITY; pConfig->DMAConfig.BurstMode = ENET_BURSTLENGTH_MIXED; pConfig->DMAConfig.RebuildINCRxBurst = ENET_FALSE; pConfig->DMAConfig.AddressAlignedBeats = ENET_FALSE; pConfig->DMAConfig.EnhancedDescriptor = ENET_FALSE; for (u8Channel = 0u; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { pConfig->DMAConfig.ChannelConfigs[u8Channel].BurstLength = ENET_DMA_BURST_LENGTH_32_BEATS; pConfig->DMAConfig.ChannelConfigs[u8Channel].EarlySendIntEnable = ENET_FALSE; pConfig->DMAConfig.ChannelConfigs[u8Channel].OperateSecondPacket = ENET_TRUE; pConfig->DMAConfig.ChannelConfigs[u8Channel].TxChannelWeight = 0u; pConfig->DMAConfig.ChannelConfigs[u8Channel].EarlyReceiveIntEnable = ENET_FALSE; } pConfig->EventCallback = NULL_PTR; pConfig->RxReady = NULL_PTR; pConfig->TxComplete = NULL_PTR; pConfig->TxCompleteWait = NULL_PTR; ENET_ASSIGNING_MEMBER(pConfig->ReleaseCallback, NULL_PTR); #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) /** * @brief Release the dynamic allocated buffers * @param[in] pEnetHandle ENET driver handle */ static void Enet_ReleaseRxDescBuffers(ENET_HandleType *pEnetHandle) { ENET_DescListType *pDescList; ENET_DMADescType *pDescArray; ENET_DMADescType *pDesc; ENET_BufferType buffer; uint8_t u8Channel; uint16_t u16RingSize; if (pEnetHandle->ReleaseCallback != NULL_PTR) { for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { pDescList = &pEnetHandle->RxDescLists[u8Channel]; pDescArray = (ENET_DMADescType *)pDescList->DescList; for (u16RingSize = 0u; u16RingSize < pDescList->RingSize; ++u16RingSize) { pDesc = &pDescArray[u16RingSize]; if (!ENET_DES_GETFLAG_RELEASED(pDesc)) { buffer.Next = NULL_PTR; buffer.Data = (uint8_t *)pDesc->BackupInfo0; ENET_DES_RESTORE_USTATE(pDesc, &buffer); buffer.Length = 0u; buffer.TotalLength = 0u; pEnetHandle->ReleaseCallback(&buffer); } } } } } #endif /** * @brief Reset ENET driver * @param[in] pEnetHandle ENET driver handle */ void Enet_DeInit(ENET_HandleType *pEnetHandle) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_DEINIT_SERVICE_ID)) { #endif Enet_Stop_Process(pEnetHandle); #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) /* Release the dynamic allocated buffers in the RX descriptors */ Enet_ReleaseRxDescBuffers(pEnetHandle); #endif pEnetHandle->EnetBase = NULL_PTR; pEnetHandle->State = ENET_STATE_UNINIT; pEnetHandle->TxState = ENET_STATE_UNINIT; pEnetHandle->RxState = ENET_STATE_UNINIT; pEnetHandle->PTPState = ENET_STATE_UNINIT; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Initialize ENET driver handle and peripheral * @param[in] pEnetHandle ENET driver handle * @param[in] pConfig ENET configure parameters * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS ENET initialize succeeded * @retval other values ENET initialize failed */ ENET_StatusType Enet_Init(ENET_HandleType *pEnetHandle, const ENET_ConfigType *pConfig) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; ENET_Type *pEnetBase[ENET_INSTANCE_COUNT] = ENET_BASE_PTRS; uint32_t CoreId; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_INIT_SERVICE_ID)) { if (pConfig == NULL_PTR) { ENET_ReportDevError(ENET_INIT_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State != ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_INIT_SERVICE_ID, ENET_E_DRIVER_REPEAT_INIT); } else { if ((pConfig->TxChannelCount == 0u) || (pConfig->TxChannelCount > ENET_CHANNEL_COUNT)) { ENET_ReportDevError(ENET_INIT_SERVICE_ID, ENET_E_PARAM_TXCHANNEL); } else { if ((pConfig->RxChannelCount == 0u) || (pConfig->RxChannelCount > ENET_CHANNEL_COUNT)) { ENET_ReportDevError(ENET_INIT_SERVICE_ID, ENET_E_PARAM_RXCHANNEL); } else { if (0u != Enet_AssertConfiguration(pConfig)) { ENET_ReportDevError(ENET_INIT_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif pEnetHandle->State = ENET_STATE_UNINIT; pEnetHandle->TxState = ENET_STATE_UNINIT; pEnetHandle->RxState = ENET_STATE_UNINIT; pEnetHandle->PTPState = ENET_STATE_UNINIT; pEnetHandle->EnetBase = pEnetBase[pEnetHandle->eInstance]; pEnetHandle->TxChannelCount = pConfig->TxChannelCount; pEnetHandle->RxChannelCount = pConfig->RxChannelCount; pEnetHandle->RxItMode = pConfig->RxIntMode; pEnetHandle->TxItMode = pConfig->TxIntMode; pEnetHandle->SendPollWait = pConfig->SendPollTimeout; pEnetHandle->VlanOpBusyWait = pConfig->VlanOpTimeout; pEnetHandle->PtpPollWait = pConfig->PtpCtrlTimeout; #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK pEnetHandle->GclBusyWait = pConfig->GclOpTimeout; #endif CoreId = ENET_HWA_Sysctrl_GetCoreId(); #if ENET_SUPPORT_TCM_SMP_MODE if (ENET_FALSE != ENET_HWA_Sysctrl_GetTcmSMPModeEnFlag()) { pEnetHandle->DtcmEntryOffset = ENET_DTCM_BACKDOOR_OFFSET(CoreId, 1u); } else #endif { pEnetHandle->DtcmEntryOffset = ENET_DTCM_BACKDOOR_OFFSET(CoreId, 0u); } Enet_SystemConfig(pConfig); /** DMA software reset */ eStatus = Enet_SoftwareReset(pEnetHandle->EnetBase, pConfig->SoftResetTimeout); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_MDIOInit(pEnetHandle, &pConfig->MiiConfig); if (ENET_STATUS_SUCCESS == eStatus) { Enet_DMARxDescInit(pEnetHandle, pConfig->RxBD); Enet_DMATxDescInit(pEnetHandle, pConfig->TxBD, pConfig->DMAConfig.EnhancedDescriptor); Enet_DMAInit(pEnetHandle, &pConfig->DMAConfig); Enet_MTLInit(pEnetHandle, &pConfig->MTLConfig); Enet_MACInit(pEnetHandle, &pConfig->MACConfig, pConfig->Speed, pConfig->Duplex); Enet_MacAddressConfig(pEnetHandle->EnetBase, pConfig->MACAddress, ENET_MAC_ADDRESS_LENGTH); pEnetHandle->EventCallback = pConfig->EventCallback; pEnetHandle->RxReady = pConfig->RxReady; pEnetHandle->TxComplete = pConfig->TxComplete; pEnetHandle->TxCompleteWait = pConfig->TxCompleteWait; ENET_ASSIGNING_MEMBER(pEnetHandle->ReleaseCallback, pConfig->ReleaseCallback); pEnetHandle->TxState = ENET_STATE_INITIALIZED; pEnetHandle->RxState = ENET_STATE_INITIALIZED; pEnetHandle->State = ENET_STATE_INITIALIZED; } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } } #endif return eStatus; } /** * @brief Initializes the ENET DMA TX descriptors * @param[in] pEnetHandle ENET driver handle * @param[in] pTxDesc An Array of TX channel descriptors configure structures */ static void Enet_DMATxDescInit(ENET_HandleType *pEnetHandle, const ENET_DescConfigType pTxDesc[], bool bEnhancedDesc) { uint8_t u8Channel; uint16_t u16RingIndex; uint16_t u16RingSize; uint16_t u16BufferLen; ENET_BufferType *pbuffer; for (u8Channel = 0u; u8Channel < pEnetHandle->TxChannelCount; ++u8Channel) { u16BufferLen = pTxDesc[u8Channel].BufferLen; u16RingSize = pTxDesc[u8Channel].RingSize; pEnetHandle->TxDescLists[u8Channel].DescList = pTxDesc[u8Channel].DescList; pEnetHandle->TxDescLists[u8Channel].BufferLen = u16BufferLen; pEnetHandle->TxDescLists[u8Channel].RingSize = u16RingSize; pEnetHandle->TxDescLists[u8Channel].CurrDesc = pTxDesc[u8Channel].DescList; pEnetHandle->TxDescLists[u8Channel].WriteBack = pTxDesc[u8Channel].CacheWriteBack; if (bEnhancedDesc) { ENET_DMAEnhancedDescType *pEdeslist = (ENET_DMAEnhancedDescType *)(pEnetHandle->TxDescLists[u8Channel].DescList); pEnetHandle->TxDescLists[u8Channel].DesMode = ENET_ENHANCED_DES_TYPE; for (u16RingIndex = 0u; u16RingIndex < u16RingSize; ++u16RingIndex) { pEdeslist[u16RingIndex].EDes4 = 0u; pEdeslist[u16RingIndex].EDes5 = 0u; pEdeslist[u16RingIndex].EDes6 = 0u; pEdeslist[u16RingIndex].EDes7 = 0u; pEdeslist[u16RingIndex].Des0 = 0u; pEdeslist[u16RingIndex].Des1 = 0u; pEdeslist[u16RingIndex].Des2 = 0u; pEdeslist[u16RingIndex].Des3 = 0u; if (pTxDesc[u8Channel].Buffers != NULL_PTR) { pbuffer = &(pTxDesc[u8Channel].Buffers[u16RingIndex]); pEdeslist[u16RingIndex].BackupInfo0 = (uint32_t)pbuffer->Data; pEdeslist[u16RingIndex].BackupInfo1 = 0u; } else { pEdeslist[u16RingIndex].BackupInfo0 = 0u; pEdeslist[u16RingIndex].BackupInfo1 = 0u; } } } else { ENET_DMADescType *pDeslist = (ENET_DMADescType *)(pEnetHandle->TxDescLists[u8Channel].DescList); pEnetHandle->TxDescLists[u8Channel].DesMode = ENET_GENERAL_DES_TYPE; for (u16RingIndex = 0u; u16RingIndex < u16RingSize; ++u16RingIndex) { pDeslist[u16RingIndex].Des0 = 0u; pDeslist[u16RingIndex].Des1 = 0u; pDeslist[u16RingIndex].Des2 = 0u; pDeslist[u16RingIndex].Des3 = 0u; if (pTxDesc[u8Channel].Buffers != NULL_PTR) { pbuffer = &(pTxDesc[u8Channel].Buffers[u16RingIndex]); pDeslist[u16RingIndex].BackupInfo0 = (uint32_t)pbuffer->Data; pDeslist[u16RingIndex].BackupInfo1 = 0u; } else { pDeslist[u16RingIndex].BackupInfo0 = 0u; pDeslist[u16RingIndex].BackupInfo1 = 0u; } } } ENET_HWA_DMA_SetTxDescListHeadAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, (uint32_t)pEnetHandle->TxDescLists[u8Channel].DescList); ENET_HWA_DMA_SetTxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, (uint32_t)pEnetHandle->TxDescLists[u8Channel].DescList); ENET_HWA_DMA_SetTxDescRingLength(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, (uint16_t)(u16RingSize - 1u)); } } /** * @brief Setup the ENET DMA RX descriptor for receiving * @param[in] pEnetHandle ENET driver handle * @param[in] pDesc Pointer to the DMA descriptor */ ENET_DECLARE_EFFICIENT_CODE( static inline void Enet_SetupRxDesc(ENET_HandleType *pEnetHandle, ENET_DMADescType *pDesc)) { pDesc->Des0 = ENET_BUFFER_DMA_ENTRY(pDesc->BackupInfo0, pEnetHandle->DtcmEntryOffset); pDesc->Des1 = 0u; pDesc->Des2 = 0u; pDesc->Des3 = ENET_RDES3_BUFFER1_VALID_MASK | ENET_DES3_OWN_MASK | ((pEnetHandle->RxItMode == ENET_INTERRUPT_MODE) ? ENET_RDES3_IOC_MASK : 0u); ENET_DES_SETFLAG_AVAILABLE(pDesc); } /** * @brief Initializes the ENET DMA TX descriptors * @param[in] pEnetHandle ENET driver handle * @param[in] pRxDesc AN array of RX channel descriptors configure structures */ static void Enet_DMARxDescInit(ENET_HandleType *pEnetHandle, const ENET_DescConfigType pRxDesc[]) { uint8_t u8Channel; uint16_t u16RingIndex; uint16_t u16RingSize; uint16_t u16BufferLen; ENET_DescListType *pRxDeslist; ENET_DMADescType *pDeslist; ENET_BufferType *pbuffer; for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { pRxDeslist = &(pEnetHandle->RxDescLists[u8Channel]); u16BufferLen = pRxDesc[u8Channel].BufferLen; u16RingSize = pRxDesc[u8Channel].RingSize; pRxDeslist->DescList = pRxDesc[u8Channel].DescList; pRxDeslist->BufferLen = u16BufferLen; pRxDeslist->RingSize = u16RingSize; pRxDeslist->CurrDesc = pRxDesc[u8Channel].DescList; pRxDeslist->DesMode = ENET_GENERAL_DES_TYPE; pRxDeslist->WriteBack = pRxDesc[u8Channel].CacheWriteBack; pDeslist = (ENET_DMADescType *)(pRxDeslist->DescList); for (u16RingIndex = 0u; u16RingIndex < u16RingSize; ++u16RingIndex) { pbuffer = &(pRxDesc[u8Channel].Buffers[u16RingIndex]); pDeslist[u16RingIndex].BackupInfo0 = (uint32_t)pbuffer->Data; ENET_DES_SAVE_USTATE(&pDeslist[u16RingIndex], pbuffer); Enet_SetupRxDesc(pEnetHandle, &pDeslist[u16RingIndex]); } ENET_HWA_DMA_SetRxDescListHeadAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, (uint32_t)pDeslist); ENET_HWA_DMA_SetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, (uint32_t)(&pDeslist[u16RingSize - 1u])); ENET_HWA_DMA_SetRxDescRingLength(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, (uint16_t)(u16RingSize - 1u)); ENET_HWA_DMA_SetRxBufferSize(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, pEnetHandle->RxDescLists[u8Channel].BufferLen); } } /** * @brief Start ENET transmission and reception * @param[in] pEnetHandle ENET driver handle * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS ENET start succeeded * @retval other values ENET start failed */ ENET_StatusType Enet_Start(ENET_HandleType *pEnetHandle) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; uint8_t u8Channel; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_START_SERVICE_ID)) { #endif if (ENET_STATE_INITIALIZED == pEnetHandle->State) { for (u8Channel = 0u; u8Channel < pEnetHandle->TxChannelCount; ++u8Channel) { if (pEnetHandle->TxItMode == ENET_INTERRUPT_MODE) { /* Enable DMA interrupts */ ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_NORMAL_INTERRUPT); ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_ABNORMAL_INTERRUPT); ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_TX_INTERRUPT); ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_FATAL_BUS_ERROR_INTERRUPT); } /* Enable DMA transmission */ ENET_HWA_DMA_StartTx(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); ENET_HWA_DMA_ClearTxProcessStoppedFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); /* Flush Transmit Queues FIFO */ ENET_HWA_MTL_FlushTxQueue(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel); } for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { if (pEnetHandle->RxItMode == ENET_INTERRUPT_MODE) { /* Enable DMA interrupts */ ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_NORMAL_INTERRUPT); ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_ABNORMAL_INTERRUPT); ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_RX_INTERRUPT); ENET_HWA_DMA_EnableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_FATAL_BUS_ERROR_INTERRUPT); } /* Enable DMA reception */ ENET_HWA_DMA_StartRx(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); ENET_HWA_DMA_ClearRxProcessStoppedFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); } /* Enable MAC transmission and reception */ ENET_HWA_MAC_SetTxEnFlag(pEnetHandle->EnetBase, ENET_TRUE); ENET_HWA_MAC_SetRxEnFlag(pEnetHandle->EnetBase, ENET_TRUE); pEnetHandle->State = ENET_STATE_READY; pEnetHandle->TxState = ENET_STATE_READY; pEnetHandle->RxState = ENET_STATE_READY; eStatus = ENET_STATUS_SUCCESS; } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif return eStatus; } /** * @brief Stop ENET transmission and reception * @param[in] pEnetHandle ENET driver handle * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS ENET Stop succeeded * @retval other values ENET Stop failed */ static ENET_StatusType Enet_Stop_Process(ENET_HandleType *pEnetHandle) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; uint8_t u8Channel; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_STOP_SERVICE_ID)) { #endif if (ENET_STATE_READY == pEnetHandle->State) { if ((ENET_STATE_BUSY != pEnetHandle->TxState) && (ENET_STATE_BUSY != pEnetHandle->RxState)) { pEnetHandle->State = ENET_STATE_BUSY; /* Disable DMA interrupts */ for (u8Channel = 0u; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { ENET_HWA_DMA_SetEnabledInterrupts(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, 0u); } /* Disable DMA transmission */ for (u8Channel = 0u; u8Channel < pEnetHandle->TxChannelCount; ++u8Channel) { ENET_HWA_DMA_StopTx(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); ENET_HWA_MTL_FlushTxQueue(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel); } /* Disable MAC transmission and reception */ ENET_HWA_MAC_SetTxEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetRxEnFlag(pEnetHandle->EnetBase, ENET_FALSE); /* Disable DMA reception */ for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { ENET_HWA_DMA_StopRx(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); ENET_HWA_DMA_ClearRxProcessStoppedFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); } pEnetHandle->State = ENET_STATE_STOPPED; pEnetHandle->TxState = ENET_STATE_STOPPED; pEnetHandle->RxState = ENET_STATE_STOPPED; eStatus = ENET_STATUS_SUCCESS; } else { eStatus = ENET_STATUS_BUSY; } } else { eStatus = ENET_STATUS_ERROR; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif return eStatus; } /** * @brief Get IEEE1588 time stamp from the ENET DMA TX descriptor * @param[in] pEnetHandle ENET driver handle * @param[in] pDesc Pointer to DMA TX descriptor * @param[in] DesMode ENET descriptor mode type, general or enchanced * @param[out] pTimestamp Time stamp value * @return boolean * @retval true Time stamp of transmitted frame is valid * @retval false Time stamp of transmitted frame is invalid */ static bool Enet_ReadTxDescTimestamp(ENET_HandleType *pEnetHandle, const ENET_DMADescPtrType DescPtr, ENET_DescModeType DesMode, ENET_TimestampType *pTimestamp) { uint32_t u32CurrTimeSec; bool bRet = false; ENET_DMADescType *pDesc; pDesc = ENET_GET_DESINFO_PTR(DescPtr, DesMode); if (((pDesc->Des3 & ENET_DES3_CTXT_MASK) == 0u) && ((pDesc->Des3 & ENET_TDES3_LD_MASK) != 0u) && ((pDesc->Des3 & ENET_TDES3_TTSS_MASK) != 0u)) { pTimestamp->Nanoseconds = pDesc->Des0; pTimestamp->Seconds = pDesc->Des1; u32CurrTimeSec = (uint32_t)(pEnetHandle->EnetBase->MAC_SYSTEM_TIME_SECONDS); pTimestamp->SecondsHi = (uint16_t)pEnetHandle->EnetBase->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS; if (pTimestamp->Seconds > u32CurrTimeSec) { pTimestamp->SecondsHi = (uint16_t)(pTimestamp->SecondsHi - 1u); } if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == ENET_HWA_MAC_GetTimestampRolloverCtrl(pEnetHandle->EnetBase)) { pTimestamp->Nanoseconds = Enet_PTPRegValue2Nanoseconds(pTimestamp->Nanoseconds); } bRet = true; } return bRet; } /** * @brief Get IEEE1588 time stamp from the ENET DMA RX descriptor * @param[in] pEnetHandle ENET driver handle * @param[in] pDesc Pointer to DMA RX descriptor * @param[out] pTimestamp Time stamp value */ ENET_DECLARE_EFFICIENT_CODE( static void Enet_ReadRxDescTimestamp(ENET_HandleType *pEnetHandle, const ENET_DMADescType *pDesc, ENET_TimestampType *pTimestamp)) { uint32_t CurrTimeSec; pTimestamp->Nanoseconds = pDesc->Des0; pTimestamp->Seconds = pDesc->Des1; CurrTimeSec = (uint32_t)(pEnetHandle->EnetBase->MAC_SYSTEM_TIME_SECONDS); pTimestamp->SecondsHi = (uint16_t)pEnetHandle->EnetBase->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS; if (pTimestamp->Seconds > CurrTimeSec) { pTimestamp->SecondsHi = (uint16_t)(pTimestamp->SecondsHi - 1u); } if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == ENET_HWA_MAC_GetTimestampRolloverCtrl(pEnetHandle->EnetBase)) { pTimestamp->Nanoseconds = Enet_PTPRegValue2Nanoseconds(pTimestamp->Nanoseconds); } } /** * @brief Get next descriptor from the descriptor list * @param[in] pCurDesc Pointer to current descriptor * @param[in] pDescList Pointer to DMA descriptors list start address * @return ENET_DMADescType * @retval Pointer to next DMA descriptor */ ENET_DECLARE_EFFICIENT_CODE( static inline ENET_DMADescType *Enet_NextDescriptor(ENET_DMADescType *pCurDesc, ENET_DescListType *pDescList)) { uint32_t pTemp; ENET_DMADescType *pDesArray; pDesArray = (ENET_DMADescType *)pDescList->DescList; pTemp = (uint32_t)(&pDesArray[pDescList->RingSize - 1u]); if ((uint32_t)pCurDesc >= pTemp) { return pDesArray; } else { return &pCurDesc[1u]; } } /** * @brief Get next TX descriptor from the descriptor list * @param[in] pCurDesc Pointer to current descriptor * @param[in] pDescList Pointer to DMA descriptors list start address * @return ENET_DMADescType * @retval Pointer to next DMA descriptor */ ENET_DECLARE_EFFICIENT_CODE( static ENET_DMADescPtrType Enet_NextTxDescriptor(ENET_DMADescPtrType pCurDesc, ENET_DescListType *pDescList)) { uint32_t pTemp; ENET_DMAEnhancedDescType *pEdesArray; if (pDescList->DesMode == ENET_GENERAL_DES_TYPE) { return (ENET_DMADescPtrType)Enet_NextDescriptor((ENET_DMADescType *)pCurDesc, pDescList); } else { pEdesArray = (ENET_DMAEnhancedDescType *)pDescList->DescList; pTemp = (uint32_t)(&pEdesArray[pDescList->RingSize - 1u]); if ((uint32_t)pCurDesc >= pTemp) { return pDescList->DescList; } else { return (ENET_DMADescPtrType)((ENET_DMAEnhancedDescType *)pCurDesc + 1u); } } } /** * @brief Setup the context descriptor before the normal tx descriptor * @param[in] pEnetHandle ENET driver handle * @param[in] pDesc Pointer to DMA descriptor * @param[in] pOption Transmit options * @param[out] pContextDesc 1: A context descriptor is added, 0: No context descriptor is added * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS A context descriptor is added, or no context descriptor is needed * @retval ENET_STATUS_ERROR The descriptor is unavailable */ ENET_DECLARE_EFFICIENT_CODE( static ENET_StatusType Enet_SetupTxContextDesc(ENET_HandleType *pEnetHandle, ENET_DMADescType *pDesc, ENET_TxOptionType *pOption, uint32_t *pContextDesc)) { ENET_StatusType eStatus = ENET_STATUS_SUCCESS; if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_VLAN_TAG_CTRL)) { /* Add context descriptor */ if (0u != (pDesc->Des3 & ENET_DES3_OWN_MASK)) { eStatus = ENET_STATUS_ERROR; } else { pDesc->Des0 = 0u; pDesc->Des1 = 0u; pDesc->Des2 = 0u; pDesc->Des3 = ENET_DES3_CTXT_MASK | ENET_DES3_OWN_MASK; if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_VLAN_TAG_CTRL)) { /* Set VLAN tag */ pDesc->Des3 |= ENET_TDES3_VT(pOption->VlanConfig.VlanTag) | ENET_TDES3_VLTV_MASK; /* Set VLAN tag input source from Tx descriptor */ ENET_HWA_MAC_SetVLANTagInputEnFlag(pEnetHandle->EnetBase, ENET_TRUE); ENET_HWA_MAC_SetVLANPriorityCtrlEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetVLANType(pEnetHandle->EnetBase, pOption->VlanConfig.VlanType); if (pOption->VlanConfig.VlanType == ENET_MAC_VLAN_TYPE_S_VLAN) { ENET_HWA_MAC_SetSVLANEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_INNER_VLAN_TAG_CTRL)) { pDesc->Des2 |= ENET_TDES2_IVT(pOption->InnerVlanConfig.VlanTag); pDesc->Des3 |= ENET_TDES3_IVLTV_MASK | ENET_TDES3_IVTIR(pOption->InnerVlanConfig.VlanCtrl); /* Set inner VLAN tag input source from Tx descriptor */ ENET_HWA_MAC_SetInnerVLANTagInputEnFlag(pEnetHandle->EnetBase, ENET_TRUE); ENET_HWA_MAC_SetInnerVLANType(pEnetHandle->EnetBase, pOption->InnerVlanConfig.VlanType); ENET_HWA_MAC_SetInnerVLANPriorityCtrlEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetDoubleVLANProcessEnFlag(pEnetHandle->EnetBase, ENET_TRUE); if (pOption->InnerVlanConfig.VlanType == ENET_MAC_VLAN_TYPE_S_VLAN) { ENET_HWA_MAC_SetSVLANEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } } } *pContextDesc = 1u; } } return eStatus; } /** * @brief Build TX descriptors to DMA * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel DMA channel to use * @param[in] pBuffers Data buffer chain to transmit * @param[inout] pOption Transmit options and results,set NULL if not needed * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS TX descriptors are prepared to DMA successfully * @retval other values TX descriptors are prepared to DMA failed */ ENET_DECLARE_EFFICIENT_CODE( static ENET_StatusType Enet_BuildTxDescriptors(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_BufferType *pBuffers, ENET_TxOptionType *pOption)) { ENET_StatusType eStatus = ENET_STATUS_SUCCESS; ENET_DescListType *pDescList; ENET_DMADescType *pDesc; ENET_BufferType *pBuf = pBuffers; uint32_t ContextDesc = 0u; uint32_t FrameLength = pBuf->TotalLength; ENET_DMADescPtrType DescPtr; ENET_DMADescPtrType pFirstDesc; ENET_DMADescPtrType pLastDesc; pDescList = &pEnetHandle->TxDescLists[eChannel]; DescPtr = (ENET_DMADescPtrType)ENET_HWA_DMA_GetTxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); pFirstDesc = DescPtr; pLastDesc = DescPtr; pDesc = ENET_GET_DESINFO_PTR(DescPtr, pDescList->DesMode); /* Add context descriptor if VLAN tag or TCP segmentation is enabled */ if (pOption != NULL_PTR) { eStatus = Enet_SetupTxContextDesc(pEnetHandle, pDesc, pOption, &ContextDesc); if (ENET_STATUS_SUCCESS == eStatus) { if (ContextDesc != 0u) { DescPtr = Enet_NextTxDescriptor(DescPtr, pDescList); pDesc = ENET_GET_DESINFO_PTR(DescPtr, pDescList->DesMode); } } } if (ENET_STATUS_SUCCESS == eStatus) { while (pBuf != NULL_PTR) { if (0u != (pDesc->Des3 & ENET_DES3_OWN_MASK)) { eStatus = ENET_STATUS_ERROR; break; } pLastDesc = DescPtr; pDesc->Des0 = ENET_BUFFER_DMA_ENTRY(pBuf->Data, pEnetHandle->DtcmEntryOffset); pDesc->Des1 = 0u; pDesc->Des2 = ENET_TDES2_BUFFER1_LEN(pBuf->Length); pDesc->Des3 = ENET_DES3_OWN_MASK | ENET_TDES3_FL(FrameLength); ENET_CLEAN_DCACHE(pBuf->Data, pBuf->Length, pDescList->WriteBack); DescPtr = Enet_NextTxDescriptor(DescPtr, pDescList); pDesc = ENET_GET_DESINFO_PTR(DescPtr, pDescList->DesMode); pBuf = pBuf->Next; } } if (ENET_STATUS_SUCCESS == eStatus) { /* Set first Descriptor */ DescPtr = pFirstDesc; if (ContextDesc != 0u) { DescPtr = Enet_NextTxDescriptor(DescPtr, pDescList); } pDesc = ENET_GET_DESINFO_PTR(DescPtr, pDescList->DesMode); pDesc->Des3 |= ENET_TDES3_FD_MASK; if (pOption != NULL_PTR) { /* Set first descriptor enable CRC pad*/ if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_CRC_PAD_CTRL)) { pDesc->Des3 |= ENET_TDES3_CPC(pOption->CrcPadCtrl); } /* Set first descriptor enable checksum */ if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_CHECKSUM_INSERTION)) { pDesc->Des3 |= ENET_TDES3_CIC(pOption->CheckSumCtrl); } /* Set first descriptor enable VLAN tag */ if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_VLAN_TAG_CTRL)) { pDesc->Des2 |= ENET_TDES2_VTIR(pOption->VlanConfig.VlanCtrl); } /* Set last descriptor enable time stamp */ if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_TIMESTAMP_SNAPSHOOT)) { ENET_GET_DESINFO_PTR(pLastDesc, pDescList->DesMode)->Des2 |= ENET_TDES2_TTSE_MASK; } } #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK /* Set launchtime */ if (pDescList->DesMode == ENET_ENHANCED_DES_TYPE) { if (0u != (pOption->Attributes & (uint32_t)ENET_TX_ATTRIBUTES_LAUNCH_TIME)) { ((ENET_DMAEnhancedDescType *)DescPtr)->EDes4 = ENET_ETDES4_GSN((ENET_HWA_MTL_GetEstCGSN(pEnetHandle->EnetBase) + pOption->GclSlotOffset) & 15u) | ENET_ETDES4_LT(pOption->LaunchTimeSec) | ENET_ETDES4_LTV_MASK; ((ENET_DMAEnhancedDescType *)DescPtr)->EDes5 = ENET_ETDES5_LT(pOption->LaunchTimeNanoSec); } else { ((ENET_DMAEnhancedDescType *)DescPtr)->EDes4 = 0u; ((ENET_DMAEnhancedDescType *)DescPtr)->EDes5 = 0u; } } #endif /* Set last descriptor interrupt */ if (pEnetHandle->TxItMode == ENET_INTERRUPT_MODE) { ENET_GET_DESINFO_PTR(pLastDesc, pDescList->DesMode)->Des2 |= ENET_TDES2_IOC_MASK; } /* Set last descriptor flag */ ENET_GET_DESINFO_PTR(pLastDesc, pDescList->DesMode)->Des3 |= ENET_TDES3_LD_MASK; pDescList->CurrDesc = pLastDesc; } else { /* Release Descriptors on error state */ DescPtr = pFirstDesc; while (DescPtr != pLastDesc) { ENET_GET_DESINFO_PTR(DescPtr, pDescList->DesMode)->Des3 &= ~ENET_DES3_OWN_MASK; DescPtr = Enet_NextTxDescriptor(DescPtr, pDescList); } ENET_GET_DESINFO_PTR(DescPtr, pDescList->DesMode)->Des3 &= ~ENET_DES3_OWN_MASK; } return eStatus; } /** * @brief ENET transmit frame * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel DMA channel to use * @param[in] pBuffers Data buffer chain to transmit,The valid buffers must be ended with NULL pointer. * The member TotalLength of the first buffer will be used by this driver. * The member Length of all buffers will be used by this driver. * The member Data of all buffers will be accessed by DMA. * It is recommended that the Data buffer be placed in a non-cacheable area, * otherwise users need to manually refresh the cache. * @param[inout] pOption Transmit options and results,set NULL if not needed * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Send frame successfully * @retval other values Send frame failed */ ENET_DECLARE_EFFICIENT_CODE( ENET_StatusType Enet_SendFrame(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_BufferType *pBuffers, ENET_TxOptionType *pOption)) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; ENET_DMADescPtrType pLastDesc = NULL_PTR; ENET_DMADescPtrType pTailDesc = NULL_PTR; uint32_t u32Timeout = pEnetHandle->SendPollWait; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SEND_FRAME_SERVICE_ID)) { if (pBuffers == NULL_PTR) { ENET_ReportDevError(ENET_SEND_FRAME_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State != ENET_STATE_READY) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_SEND_FRAME_SERVICE_ID, ENET_E_CONTROLLER_MODE); } else { if ((uint8_t)eChannel >= pEnetHandle->TxChannelCount) { ENET_ReportDevError(ENET_SEND_FRAME_SERVICE_ID, ENET_E_PARAM_TXCHANNEL); } else { if (0u != Enet_AssertTxBuffer(pEnetHandle, eChannel, pBuffers)) { ENET_ReportDevError(ENET_SEND_FRAME_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else if (0u != Enet_AssertTxOption(pEnetHandle, pOption)) { ENET_ReportDevError(ENET_SEND_FRAME_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif if (ENET_STATE_READY == pEnetHandle->TxState) { pEnetHandle->TxState = ENET_STATE_BUSY; eStatus = Enet_BuildTxDescriptors(pEnetHandle, eChannel, pBuffers, pOption); if (ENET_STATUS_SUCCESS == eStatus) { pLastDesc = pEnetHandle->TxDescLists[eChannel].CurrDesc; if (pLastDesc != NULL_PTR) { pTailDesc = Enet_NextTxDescriptor(pLastDesc, &pEnetHandle->TxDescLists[(uint32_t)eChannel]); ENET_DATA_BARRIER(); ENET_HWA_DMA_SetTxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel, (uint32_t)pTailDesc); if (pEnetHandle->TxItMode == ENET_INTERRUPT_MODE) { /* Call WaitTxCompleteCallback for TX time stamp valid */ if (pEnetHandle->TxCompleteWait != NULL_PTR) { eStatus = pEnetHandle->TxCompleteWait(pEnetHandle, eChannel); } } else if (pEnetHandle->TxItMode == ENET_POLLING_MODE) { /* Poll DMA send complete */ while ((ENET_GET_DESINFO_PTR(pLastDesc, pEnetHandle->TxDescLists[eChannel].DesMode)->Des3 & ENET_DES3_OWN_MASK) != (uint32_t)0u) { if (--u32Timeout == 0u) { eStatus = ENET_STATUS_TIMEOUT; break; } } } else { /* Polling with back to back mode */ } } else { eStatus = ENET_STATUS_ERROR; } } if ((ENET_STATUS_SUCCESS == eStatus) && (pOption != NULL_PTR)) { pOption->Attributes = 0u; /* read IEEE1588 time stamp */ if (Enet_ReadTxDescTimestamp(pEnetHandle, pLastDesc, pEnetHandle->TxDescLists[eChannel].DesMode, &pOption->TimeStamp) != false) { pOption->Attributes |= (uint32_t)ENET_TX_ATTRIBUTES_TIMESTAMP_VALID; } } pEnetHandle->TxState = ENET_STATE_READY; } else { eStatus = ENET_STATUS_BUSY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } /** * @brief Release RX descriptors to DMA * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel DMA channel to use * @param[in] pStart Pointer to the first descriptor * @param[inout] pEnd Pointer to the last descriptor */ ENET_DECLARE_EFFICIENT_CODE( static void Enet_ReleaseRxDescriptors(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_DMADescType *pStart, ENET_DMADescType *pEnd)) { ENET_DMADescType *pDesc; if ((pStart != NULL_PTR) && (pEnd != NULL_PTR)) { pDesc = pStart; while (pDesc != pEnd) { Enet_SetupRxDesc(pEnetHandle, pDesc); pDesc = Enet_NextDescriptor(pDesc, &pEnetHandle->RxDescLists[eChannel]); } Enet_SetupRxDesc(pEnetHandle, pDesc); ENET_HWA_DMA_SetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel, (uint32_t)pDesc); } } /** * @brief Get available data from DMA RX descriptors * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel DMA channel to use * @param[out] pBuffers Buffer chain to receive data * @param[out] pInfo Received data information * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Receive frame successfully * @retval other values No frame is available,or an error occurred */ ENET_DECLARE_EFFICIENT_CODE( static ENET_StatusType Enet_GetRxBuffers(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_BufferType *pBuffers, ENET_RxInfoType *pInfo)) { ENET_StatusType eStatus = ENET_STATUS_ERROR; ENET_DescListType *pDescList; ENET_DMADescType *pDescTail; ENET_DMADescType *pDesc; ENET_BufferType *pBuf = pBuffers; uint16_t u32AccumulatedLen = 0u; ENET_DMADescType *pFirstDesc; ENET_DMADescType *pLastDesc; pDescList = &pEnetHandle->RxDescLists[eChannel]; pDescTail = (ENET_DMADescType *)ENET_HWA_DMA_GetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); pDesc = (ENET_DMADescType *)pDescList->CurrDesc; pFirstDesc = NULL_PTR; pLastDesc = NULL_PTR; while (((pDesc->Des3 & ENET_DES3_OWN_MASK) == 0u) && (pBuf != NULL_PTR) && (pDesc != pDescTail)) { /* Handle LD descriptor */ if ((pDesc->Des3 & ENET_RDES3_LD_MASK) != 0u) { if (((pDesc->Des3 & ENET_RDES3_FD_MASK) != 0u) || (pFirstDesc != NULL_PTR)) { /* Single descriptor frame */ if ((pDesc->Des3 & ENET_RDES3_FD_MASK) != 0u) { if (pFirstDesc != NULL_PTR) { Enet_ReleaseRxDescriptors(pEnetHandle, eChannel, pFirstDesc, pLastDesc); } pFirstDesc = (ENET_DMADescPtrType)pDesc; pBuf = pBuffers; u32AccumulatedLen = 0u; } pLastDesc = (ENET_DMADescPtrType)pDesc; pBuffers->TotalLength = (uint16_t)(pDesc->Des3 & ENET_RDES3_PACKET_LENGTH_MASK); pBuf->Data = (uint8_t *)(pDesc->BackupInfo0); pBuf->Length = (uint16_t)(pBuffers->TotalLength - u32AccumulatedLen); pBuf->Next = NULL_PTR; ENET_DES_RESTORE_USTATE(pDesc, pBuf); ENET_DES_SETFLAG_RELEASED(pDesc); ENET_INVALIDATE_DCACHE(pBuf->Data, pBuf->Length); /* Check following descriptor is context descriptor or not */ if (pDesc->Des1 & ENET_RDES1_TIMESTAMP_AVAILABLE_MASK) { pDesc = Enet_NextDescriptor(pDesc, pDescList); if ((pDesc->Des3 & (ENET_DES3_OWN_MASK | ENET_DES3_CTXT_MASK)) == ENET_DES3_CTXT_MASK) { pLastDesc = (ENET_DMADescPtrType)pDesc; if (pInfo != NULL_PTR) { Enet_ReadRxDescTimestamp(pEnetHandle, pDesc, &pInfo->TimeStamp); pInfo->Attributes = (uint32_t)ENET_RX_ATTRIBUTES_TIMESTAMP_VALID; } } } pDescList->CurrDesc = (ENET_DMADescPtrType)Enet_NextDescriptor(pLastDesc, pDescList); eStatus = ENET_STATUS_SUCCESS; break; } else { /* NO FD descriptor found, release current descriptor and jump to next descriptor */ Enet_ReleaseRxDescriptors(pEnetHandle, eChannel, pDesc, pDesc); pLastDesc = NULL_PTR; pDesc = Enet_NextDescriptor(pDesc, pDescList); } } /* Handle FD descriptor */ else if ((pDesc->Des3 & ENET_RDES3_FD_MASK) != 0u) { if (pFirstDesc != NULL_PTR) { /* continuous FD descriptors with no LD descriptor, eg: FD ... FD .. LD */ Enet_ReleaseRxDescriptors(pEnetHandle, eChannel, pFirstDesc, pLastDesc); } /* Start receive data */ pBuf = pBuffers; pFirstDesc = (ENET_DMADescPtrType)pDesc; pLastDesc = (ENET_DMADescPtrType)pDesc; u32AccumulatedLen = (uint16_t)(pDesc->Des3 & ENET_RDES3_PACKET_LENGTH_MASK); pBuf->Data = (uint8_t *)pDesc->BackupInfo0; pBuf->Length = pDescList->BufferLen; ENET_DES_RESTORE_USTATE(pDesc, pBuf); ENET_DES_SETFLAG_RELEASED(pDesc); ENET_INVALIDATE_DCACHE(pBuf->Data, pBuf->Length); pBuf = pBuf->Next; pDesc = Enet_NextDescriptor(pDesc, pDescList); } /* Handle descriptor with FD LD not set */ else { if (pFirstDesc == NULL_PTR) { /* First descriptor not found,release current descriptor to DMA */ Enet_ReleaseRxDescriptors(pEnetHandle, eChannel, pDesc, pDesc); pDesc = Enet_NextDescriptor(pDesc, pDescList); } else { /* Handle descriptors between FD and LD */ if ((pDesc->Des3 & ENET_DES3_CTXT_MASK) == 0u) { pLastDesc = (ENET_DMADescPtrType)pDesc; u32AccumulatedLen = (uint16_t)(pDesc->Des3 & ENET_RDES3_PACKET_LENGTH_MASK); pBuf->Data = (uint8_t *)pDesc->BackupInfo0; pBuf->Length = pDescList->BufferLen; ENET_DES_RESTORE_USTATE(pDesc, pBuf); ENET_DES_SETFLAG_RELEASED(pDesc); ENET_INVALIDATE_DCACHE(pBuf->Data, pBuf->Length); pBuf = pBuf->Next; } else { /* Abnormal context descriptor,handle nothing */ pLastDesc = (ENET_DMADescPtrType)pDesc; } pDesc = Enet_NextDescriptor(pDesc, pDescList); } } } /* If receive failed, release RX descriptors */ if (ENET_STATUS_SUCCESS != eStatus) { Enet_ReleaseRxDescriptors(pEnetHandle, eChannel, pFirstDesc, pLastDesc); } return eStatus; } /** * @brief Read frame from ENET * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel DMA channel to use * @param[out] pBuffers Buffer chain to receive data,The valid buffers must be ended with NULL pointer. * The member TotalLength of the first buffer will be assigned by this driver. * The member Length of available buffers will be assigned by this driver. * The member Data of available buffers will be filled by DMA. * @param[out] pInfo Received frame information,set NULL if not needed * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Receive frame successfully * @retval other values Receive frame failed */ ENET_DECLARE_EFFICIENT_CODE( ENET_StatusType Enet_ReadFrame(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_BufferType *pBuffers, ENET_RxInfoType *pInfo)) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_READ_FRAME_SERVICE_ID)) { if (pBuffers == NULL_PTR) { ENET_ReportDevError(ENET_READ_FRAME_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State != ENET_STATE_READY) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_READ_FRAME_SERVICE_ID, ENET_E_CONTROLLER_MODE); } else { if (eChannel >= pEnetHandle->RxChannelCount) { ENET_ReportDevError(ENET_READ_FRAME_SERVICE_ID, ENET_E_PARAM_RXCHANNEL); } else { #endif if (ENET_STATE_READY == pEnetHandle->RxState) { pEnetHandle->RxState = ENET_STATE_BUSY; if (pInfo != NULL_PTR) { pInfo->Attributes = (uint32_t)0u; } eStatus = Enet_GetRxBuffers(pEnetHandle, eChannel, pBuffers, pInfo); pEnetHandle->RxState = ENET_STATE_READY; } else { eStatus = ENET_STATUS_BUSY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Build RX Descriptors to DMA * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel DMA channel to use * @param[in] pBuffers A chain of buffers to build the RX descriptors * @return ENET_BuildRxDesType * @retval ENET_BUILD_RXDES_SUCCEESS Build RX Descriptors successfully * @retval ENET_BUILD_RXDES_MORE_BUFFER Build RX Descriptors successfully and more buffer is needed * @retval ENET_BUILD_RXDES_FAILED Build RX Descriptors failed */ ENET_DECLARE_EFFICIENT_CODE( ENET_BuildRxDesType Enet_BuildRxDescriptors(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) , ENET_BufferType *pBuffers #endif )) { ENET_DescListType *pDescList; ENET_DMADescType *pDesc; ENET_BuildRxDesType eStatus = ENET_BUILD_RXDES_FAILED; ENET_DECLARE_MEMBER(ENET_BufferType *, pBuf) #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_BUILD_RXDESC_SERVICE_ID)) { if (pEnetHandle->State != ENET_STATE_READY) { ENET_ReportDevError(ENET_BUILD_RXDESC_SERVICE_ID, ENET_E_CONTROLLER_MODE); } else { if (eChannel >= pEnetHandle->RxChannelCount) { ENET_ReportDevError(ENET_BUILD_RXDESC_SERVICE_ID, ENET_E_PARAM_RXCHANNEL); } #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_ON) else if (0u != Enet_AssertRxBuffer(pEnetHandle, eChannel, pBuffers)) { ENET_ReportDevError(ENET_BUILD_RXDESC_SERVICE_ID, ENET_E_PARAM_ASSERTION); } #endif else { #endif if (ENET_STATE_READY == pEnetHandle->RxState) { eStatus = ENET_BUILD_RXDES_SUCCEESS; pDescList = &pEnetHandle->RxDescLists[eChannel]; pDesc = (ENET_DMADescType *)ENET_HWA_DMA_GetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); pDesc = Enet_NextDescriptor(pDesc, pDescList); #if (ENET_BUFFER_DYNAMIC_ALLOCATION == STD_OFF) while (pDesc != (ENET_DMADescType *)pDescList->CurrDesc) { Enet_SetupRxDesc(pEnetHandle, pDesc); ENET_HWA_DMA_SetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel, (uint32_t)pDesc); pDesc = Enet_NextDescriptor(pDesc, pDescList); } #else pBuf = pBuffers; while (pDesc != (ENET_DMADescType *)pDescList->CurrDesc) { if (ENET_DES_GETFLAG_RELEASED(pDesc)) { if (pBuf != NULL_PTR) { pDesc->BackupInfo0 = (uint32_t)pBuf->Data; ENET_DES_SAVE_USTATE(pDesc, pBuf); Enet_SetupRxDesc(pEnetHandle, pDesc); ENET_HWA_DMA_SetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel, (uint32_t)pDesc); pBuf = pBuf->Next; } else { eStatus = ENET_BUILD_RXDES_MORE_BUFFER; break; } } else { Enet_SetupRxDesc(pEnetHandle, pDesc); ENET_HWA_DMA_SetRxDescListTailAddr(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel, (uint32_t)pDesc); } pDesc = Enet_NextDescriptor(pDesc, pDescList); } #endif /* ENET_BUFFER_DYNAMIC_ALLOCATION */ } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Get MDIO bus default configuration * @param[out] pMiiConfig MDIO configure parameters */ void Enet_MDIODefaultConfig(ENET_MiiConfigType *pMiiConfig) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (pMiiConfig == NULL_PTR) { ENET_ReportDevError(ENET_MDIO_DEFCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { #endif pMiiConfig->PreambleSuppress = false; pMiiConfig->BackToBack = false; pMiiConfig->TrailingClocks = 0u; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Initialize the MDIO bus * @param[in] pEnetHandle ENET driver handle * @param[in] pMiiConfig MDIO configure parameters * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Initialize the MDIO bus successfully * @retval other values Initialize the MDIO bus failed */ ENET_StatusType Enet_MDIOInit(ENET_HandleType *pEnetHandle, const ENET_MiiConfigType *pMiiConfig) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; uint8_t i; uint8_t u8Csr = ENET_MAC_CSR_CLOCK_RANGE_100_150MHZ; uint32_t u32CsrClk; ENET_Type *pEnetBase[ENET_INSTANCE_COUNT] = ENET_BASE_PTRS; const uint32_t FreqRange[] = { 35000000u, 60000000u, 100000000u, 150000000u, 250000000u, 300000000u }; const uint8_t CsrValues[] = { (uint8_t)ENET_MAC_CSR_CLOCK_RANGE_20_35MHZ, (uint8_t)ENET_MAC_CSR_CLOCK_RANGE_35_60MHZ, (uint8_t)ENET_MAC_CSR_CLOCK_RANGE_60_100MHZ, (uint8_t)ENET_MAC_CSR_CLOCK_RANGE_100_150MHZ, (uint8_t)ENET_MAC_CSR_CLOCK_RANGE_150_250MHZ, (uint8_t)ENET_MAC_CSR_CLOCK_RANGE_250_300MHZ }; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MDIO_INIT_SERVICE_ID)) { if (pMiiConfig == NULL_PTR) { ENET_ReportDevError(ENET_MDIO_INIT_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if ((pMiiConfig->TrailingClocks >= (1u << ENET_MAC_MDIO_ADDRESS_NTC_WIDTH)) || (pMiiConfig->TrailingClocks == 0u && pMiiConfig->BackToBack == true)) { ENET_ReportDevError(ENET_MDIO_INIT_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif if (pEnetHandle->EnetBase == NULL_PTR) { pEnetHandle->EnetBase = pEnetBase[pEnetHandle->eInstance]; } #if ENET_CSR_INTERFACE_CORE_CLOCK u32CsrClk = SCG_GetScgClockFreq(SCG_CORE_CLK); #else u32CsrClk = SCG_GetScgClockFreq(SCG_BUS_CLK); #endif if (u32CsrClk != 0u) { for (i = 0u; i < sizeof(FreqRange) / sizeof(uint32_t); ++i) { if (u32CsrClk <= FreqRange[i]) { u8Csr = CsrValues[i]; break; } } ENET_HWA_MAC_SetMDIOAddress(pEnetHandle->EnetBase, ENET_MAC_MDIO_ADDRESS_PSE(pMiiConfig->PreambleSuppress ? 1u : 0u) | ENET_MAC_MDIO_ADDRESS_BTB(pMiiConfig->BackToBack ? 1u : 0u) | ENET_MAC_MDIO_ADDRESS_NTC(pMiiConfig->TrailingClocks) | ENET_MAC_MDIO_ADDRESS_CR(u8Csr)); eStatus = ENET_STATUS_SUCCESS; } else { eStatus = ENET_STATUS_ERROR; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Writes the MDIO bus access register * @param[in] pBase ENET base * @param[in] bClause45 Enable clause 45 mode * @param[in] u8Opt MDIO operation,read write or read increment address * @param[in] u8PhyAddr PHY device address * @param[in] u16PhyReg PHY register address * @param[in] u8MmdAddr Clause 45 MMD address * @param[in] pData Data to write * @param[in] u32TimeoutUs Wait time out value in microsecond * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS MDIO write successfully * @retval other values MDIO write failed */ static ENET_StatusType Enet_MDIOWriteAddress(ENET_Type *pBase, bool bClause45, ENET_MiiOptType u8Opt, uint8_t u8PhyAddr, uint16_t u16PhyReg, uint8_t u8MmdAddr, uint16_t *pData, uint32_t u32TimeoutUs) { uint32_t AddressReg = 0u, DataReg = 0u; ENET_StatusType eStatus = ENET_STATUS_SUCCESS; AddressReg = ENET_HWA_MAC_GetMDIOAddress(pBase); AddressReg &= ~(ENET_MAC_MDIO_ADDRESS_PA_MASK | ENET_MAC_MDIO_ADDRESS_RDA_MASK | ENET_MAC_MDIO_ADDRESS_GOC_0_MASK | ENET_MAC_MDIO_ADDRESS_GOC_1_MASK | ENET_MAC_MDIO_ADDRESS_C45E_MASK); AddressReg |= ENET_MAC_MDIO_ADDRESS_C45E(bClause45 ? 1u : 0u) | (uint32_t)u8Opt | ENET_MAC_MDIO_ADDRESS_PA(u8PhyAddr) | ENET_MAC_MDIO_ADDRESS_RDA(bClause45 ? u8MmdAddr : u16PhyReg) | ENET_MAC_MDIO_ADDRESS_GB_MASK; if (bClause45 || (ENET_MII_WRITE == u8Opt)) { DataReg = ENET_MAC_MDIO_DATA_RA(bClause45 ? u16PhyReg : 0u) | ENET_MAC_MDIO_DATA_GD((ENET_MII_WRITE == u8Opt) ? *pData : 0u); ENET_HWA_MAC_SetMDIOData(pBase, DataReg); } ENET_HWA_MAC_SetMDIOAddress(pBase, AddressReg); /* Wait for completion */ while (0u != (ENET_HWA_MAC_GetMDIOAddress(pBase) & ENET_MAC_MDIO_ADDRESS_GB_MASK)) { if (--u32TimeoutUs == 0u) { eStatus = ENET_STATUS_TIMEOUT; break; } } return eStatus; } /** * @brief Read the PHY register using clause 22 * @param[in] pEnetHandle ENET driver handle * @param[in] u8PhyAddr PHY device address * @param[in] u8PhyReg PHY register address * @param[in] pData Data buffer * @param[in] u32TimeoutUs Wait time out value in microsecond * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS DMIO read successfully * @retval other values DMIO read failed */ ENET_StatusType Enet_MDIORead(ENET_HandleType *pEnetHandle, uint8_t u8PhyAddr, uint8_t u8PhyReg, uint16_t *pData, uint32_t u32TimeoutUs) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MDIO_READ_SERVICE_ID)) { if (pData == NULL_PTR) { ENET_ReportDevError(ENET_MDIO_READ_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if ((u8PhyAddr >= 32u) || (u8PhyReg >= 32u)) { ENET_ReportDevError(ENET_MDIO_READ_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->EnetBase == NULL_PTR) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_MDIO_READ_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif eStatus = Enet_MDIOWriteAddress(pEnetHandle->EnetBase, false, ENET_MII_READ, u8PhyAddr, (uint16_t)u8PhyReg, 0u, pData, u32TimeoutUs); if (eStatus == ENET_STATUS_SUCCESS) { *pData = (uint16_t)ENET_HWA_MAC_GetMDIOData(pEnetHandle->EnetBase); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Write the PHY register using clause 22 * @param[in] pEnetHandle ENET driver handle * @param[in] u8PhyAddr PHY device address * @param[in] u8PhyReg PHY register address * @param[in] u16Data Data to write * @param[in] u32TimeoutUs Wait time out value in microsecond * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS DMIO write successfully * @retval other values DMIO write failed */ ENET_StatusType Enet_MDIOWrite(ENET_HandleType *pEnetHandle, uint8_t u8PhyAddr, uint8_t u8PhyReg, uint16_t u16Data, uint32_t u32TimeoutUs) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MDIO_WRITE_SERVICE_ID)) { if ((u8PhyAddr >= 32u) || (u8PhyReg >= 32u)) { ENET_ReportDevError(ENET_MDIO_WRITE_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->EnetBase == NULL_PTR) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_MDIO_WRITE_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif eStatus = Enet_MDIOWriteAddress(pEnetHandle->EnetBase, false, ENET_MII_WRITE, u8PhyAddr, (uint16_t)u8PhyReg, 0u, &u16Data, u32TimeoutUs); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Read the PHY register using clause 45 * @param[in] pEnetHandle ENET driver handle * @param[in] u8PhyAddr PHY device address * @param[in] u8Mmd MMD device address * @param[in] u16PhyReg PHY register address * @param[in] pData Data buffer * @param[in] u32TimeoutUs Wait time out value in microsecond * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS DMIO read successfully * @retval other values DMIO read failed */ ENET_StatusType Enet_MMDRead(ENET_HandleType *pEnetHandle, uint8_t u8PhyAddr, uint8_t u8Mmd, uint16_t u16PhyReg, uint16_t *pData, uint32_t u32TimeoutUs) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMD_READ_SERVICE_ID)) { if (pData == NULL_PTR) { ENET_ReportDevError(ENET_MMD_READ_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (u8PhyAddr >= 32u) { ENET_ReportDevError(ENET_MMD_READ_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->EnetBase == NULL_PTR) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_MMD_READ_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif eStatus = Enet_MDIOWriteAddress(pEnetHandle->EnetBase, true, ENET_MII_READ, u8PhyAddr, u16PhyReg, u8Mmd, pData, u32TimeoutUs); if (eStatus == ENET_STATUS_SUCCESS) { *pData = (uint16_t)ENET_HWA_MAC_GetMDIOData(pEnetHandle->EnetBase); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Write the PHY register using clause 45 * @param[in] pEnetHandle ENET driver handle * @param[in] u8PhyAddr PHY device address * @param[in] u8Mmd MMD device address * @param[in] u16PhyReg PHY register address * @param[in] u16Data Data to write * @param[in] u32TimeoutUs Wait time out value in microsecond * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS DMIO write successfully * @retval other values DMIO write failed */ ENET_StatusType Enet_MMDWrite(ENET_HandleType *pEnetHandle, uint8_t u8PhyAddr, uint8_t u8Mmd, uint16_t u16PhyReg, uint16_t u16Data, uint32_t u32TimeoutUs) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMD_WRITE_SERVICE_ID)) { if (u8PhyAddr >= 32u) { ENET_ReportDevError(ENET_MMD_WRITE_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->EnetBase == NULL_PTR) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_MMD_WRITE_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif eStatus = Enet_MDIOWriteAddress(pEnetHandle->EnetBase, true, ENET_MII_WRITE, u8PhyAddr, u16PhyReg, u8Mmd, &u16Data, u32TimeoutUs); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Set MAC0 address * @param[in] EnetBase ENET register base address * @param[in] pMacAddr MAC address * @param[in] u8MacLen MAC address length */ static void Enet_MacAddressConfig(ENET_Type *EnetBase, const uint8_t *pMacAddr, uint8_t u8MacLen) { uint32_t u32RegVal; (void)u8MacLen; /* Set physical address high register. */ u32RegVal = (uint32_t)pMacAddr[4u] | ((uint32_t)pMacAddr[5u] << 8u) | ENET_MAC_ADDRESS0_HIGH_AE_MASK; ENET_HWA_MAC_SetAddr0High(EnetBase, u32RegVal); /* Set physical address lower register. */ u32RegVal = (uint32_t)pMacAddr[0u] | ((uint32_t)pMacAddr[1u] << 8u) | ((uint32_t)pMacAddr[2u] << 16u) | ((uint32_t)pMacAddr[3u] << 24u); ENET_HWA_MAC_SetMacAddr0Low(EnetBase, u32RegVal); } /** * @brief Set MAC0 address * @param[in] pEnetHandle ENET driver handle * @param[in] pMacAddr MAC address * @param[in] u8MacLen MAC address length */ void Enet_SetMacAddress(ENET_HandleType *pEnetHandle, const uint8_t *pMacAddr, uint8_t u8MacLen) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_MACADDR_SERVICE_ID)) { if (pMacAddr == NULL_PTR) { ENET_ReportDevError(ENET_SET_MACADDR_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (u8MacLen != ENET_MAC_ADDRESS_LENGTH) { ENET_ReportDevError(ENET_SET_MACADDR_SERVICE_ID, ENET_E_PARAM_MACLEN); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_MACADDR_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif Enet_MacAddressConfig(pEnetHandle->EnetBase, pMacAddr, u8MacLen); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Enable TCPIP checksum error filter * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel ENET channel * @param[in] bEnable Enable MAC to drop packets with checksum error */ void Enet_CheckSumErrorFilter(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, bool bEnable) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_CKSUM_ERROR_FILTER_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_CKSUM_ERROR_FILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if ((uint8_t)eChannel >= pEnetHandle->RxChannelCount) { ENET_ReportDevError(ENET_CKSUM_ERROR_FILTER_SERVICE_ID, ENET_E_PARAM_RXCHANNEL); } else { #endif ENET_HWA_MTL_SetForwardTCPChecksumErrorPacketEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)eChannel, !bEnable); if (bEnable) { ENET_HWA_MAC_SetIPChecksumOffloadEnFlag(pEnetHandle->EnetBase, bEnable); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif } /** * @brief Compute CRC value * @param[in] pData Pointer to data * @param[in] u32BitLen Data bits length */ static uint32_t Enet_ComputeCRC(const uint8_t *pData, uint32_t u32BitLen) { uint32_t u32Crc = 0xFFFFFFFFu; uint32_t i, j, bytes, bits; bytes = (u32BitLen + 0x7u) >> 3u; for (i = 0u; i < bytes; ++i) { u32Crc = u32Crc ^ pData[i]; bits = (u32BitLen >= 0x8u) ? 0x8u : u32BitLen; for (j = 0u; j < bits; ++j) { if ((u32Crc & 0x1u) != 0u) { u32Crc = (u32Crc >> 1u) ^ 0xEDB88320u; } else { u32Crc = (u32Crc >> 1u); } } u32BitLen -= bits; } return ~u32Crc; } /** * @brief Reverse bits of uint32_t * @param[in] u32Data Original data * @return Reversed data */ static inline uint32_t Enet_BitsReverse(uint32_t u32Data) { uint32_t u32Tmp = u32Data; u32Tmp = (((u32Tmp & (0xAAAAAAAAu)) >> 1u) | ((u32Tmp & (0x55555555u)) << 1u)); u32Tmp = (((u32Tmp & (0xCCCCCCCCu)) >> 2u) | ((u32Tmp & (0x33333333u)) << 2u)); u32Tmp = (((u32Tmp & (0xF0F0F0F0u)) >> 4u) | ((u32Tmp & (0x0F0F0F0Fu)) << 4u)); u32Tmp = (((u32Tmp & (0xFF00FF00u)) >> 8u) | ((u32Tmp & (0x00FF00FFu)) << 8u)); return ((u32Tmp >> 16u) | (u32Tmp << 16u)); } /** * @brief Set hash table for MAC hash filter * @param[in] pEnetHandle ENET driver handle * @param[in] bAddOrRemove true: add,false: remove * @param[in] pMacAddr MAC address * @param[in] u8MacLen MAC address length */ void Enet_SetMacHashTable(ENET_HandleType *pEnetHandle, bool bAddOrRemove, const uint8_t *pMacAddr, uint8_t u8MacLen) { volatile uint32_t *pHashTable; uint32_t u32CrcVal; uint32_t u32Index, u32HashBit; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_MACHASH_SERVICE_ID)) { if (pMacAddr == NULL_PTR) { ENET_ReportDevError(ENET_SET_MACHASH_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (u8MacLen != ENET_MAC_ADDRESS_LENGTH) { ENET_ReportDevError(ENET_SET_MACHASH_SERVICE_ID, ENET_E_PARAM_MACLEN); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_MACHASH_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #else (void)u8MacLen; #endif pHashTable = (volatile uint32_t *)&pEnetHandle->EnetBase->MAC_HASH_TABLE_REG0; u32CrcVal = Enet_ComputeCRC(pMacAddr, ENET_MAC_ADDRESS_LENGTH * 0x8u); u32CrcVal = Enet_BitsReverse(u32CrcVal); u32Index = (u32CrcVal >> ENET_MAC_HASH_TABLE_INDEX_SHIFT) & ENET_MAC_HASH_TABLE_INDEX_MASK; u32HashBit = (u32CrcVal >> ENET_MAC_HASH_TABLE_BIT_SHIFT) & ENET_MAC_HASH_TABLE_BIT_MASK; if (bAddOrRemove) { pHashTable[u32Index] |= 1u << u32HashBit; } else { pHashTable[u32Index] &= ~(1u << u32HashBit); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Get default MAC filter configurations * @param[in] pMACFilter MAC filter Default configurations */ void Enet_DefaultMACFilter(ENET_MACFilterType *pMACFilter) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (pMACFilter == NULL_PTR) { ENET_ReportDevError(ENET_DEFAULT_MACFILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { #endif pMACFilter->ReceiveAll = ENET_FALSE; pMACFilter->DropNonTcpUdpOverIp = ENET_FALSE; pMACFilter->HashOrPerfectFilter = ENET_TRUE; pMACFilter->SAFilter = ENET_FILTER_DISABLE; pMACFilter->PassCtrlPkts = ENET_MAC_CTRL_PACKET_FILTER_ALL; pMACFilter->DisableBroadcast = ENET_FALSE; pMACFilter->PassAllMulticast = ENET_FALSE; pMACFilter->DAFilter = ENET_FILTER_ENABLE; pMACFilter->HashMulticast = ENET_TRUE; pMACFilter->HashUnicast = ENET_FALSE; pMACFilter->PromiscuousMode = ENET_FALSE; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Get current MAC filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pMACFilter MAC filter Current configurations */ void Enet_GetMACFilter(const ENET_HandleType *pEnetHandle, ENET_MACFilterType *pMACFilter) { uint32_t u32FilterCtrl, u32Temp; bool bInverse; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_MACFILTER_SERVICE_ID)) { if (pMACFilter == NULL_PTR) { ENET_ReportDevError(ENET_GET_MACFILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_GET_MACFILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif u32FilterCtrl = ENET_HWA_MAC_GetPacketFilter(pEnetHandle->EnetBase); pMACFilter->ReceiveAll = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_RA_MASK); pMACFilter->PromiscuousMode = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_PR_MASK); pMACFilter->DropNonTcpUdpOverIp = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_DNTU_MASK); pMACFilter->HashOrPerfectFilter = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_HPF_MASK); bInverse = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_SAIF_MASK); pMACFilter->SAFilter = (0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_SAF_MASK)) ? (bInverse ? ENET_FILTER_INVERSE_ENABLE : ENET_FILTER_ENABLE) : ENET_FILTER_DISABLE; u32Temp = (u32FilterCtrl & ENET_MAC_PACKET_FILTER_PCF_MASK) >> ENET_MAC_PACKET_FILTER_PCF_SHIFT; pMACFilter->PassCtrlPkts = (ENET_MAC_CtrlPacketFilterModeType)u32Temp; pMACFilter->DisableBroadcast = (u32FilterCtrl & ENET_MAC_PACKET_FILTER_DBF_MASK) != 0u ? true : false; pMACFilter->PassAllMulticast = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_PM_MASK); pMACFilter->DAFilter = (0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_DAIF_MASK)) ? ENET_FILTER_INVERSE_ENABLE : ENET_FILTER_ENABLE; pMACFilter->HashMulticast = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_HMC_MASK); pMACFilter->HashUnicast = 0u != (u32FilterCtrl & ENET_MAC_PACKET_FILTER_HUC_MASK); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif } /** * @brief Configure the MAC filter register * @param[in] pEnetBase ENET register base address * @param[in] pMACFilter MAC filter configurations */ static inline void Enet_MACFilterConfig(ENET_Type *pEnetBase, const ENET_MACFilterType *pMACFilter) { uint32_t u32FilterCtrl; u32FilterCtrl = ENET_HWA_MAC_GetPacketFilter(pEnetBase); u32FilterCtrl &= ~(ENET_MAC_PACKET_FILTER_RA_MASK | ENET_MAC_PACKET_FILTER_DNTU_MASK | ENET_MAC_PACKET_FILTER_HPF_MASK | ENET_MAC_PACKET_FILTER_SAF_MASK | ENET_MAC_PACKET_FILTER_SAIF_MASK | ENET_MAC_PACKET_FILTER_PCF_MASK | ENET_MAC_PACKET_FILTER_DBF_MASK | ENET_MAC_PACKET_FILTER_PM_MASK | ENET_MAC_PACKET_FILTER_DAIF_MASK | ENET_MAC_PACKET_FILTER_HMC_MASK | ENET_MAC_PACKET_FILTER_HUC_MASK | ENET_MAC_PACKET_FILTER_PR_MASK); u32FilterCtrl |= ENET_MAC_PACKET_FILTER_RA(pMACFilter->ReceiveAll ? 1u : 0u) | ENET_MAC_PACKET_FILTER_DNTU(pMACFilter->DropNonTcpUdpOverIp ? 1u : 0u) | ENET_MAC_PACKET_FILTER_HPF(pMACFilter->HashOrPerfectFilter ? 1u : 0u) | ENET_MAC_PACKET_FILTER_SAF(pMACFilter->SAFilter != ENET_FILTER_DISABLE ? 1u : 0u) | ENET_MAC_PACKET_FILTER_SAIF(pMACFilter->SAFilter == ENET_FILTER_INVERSE_ENABLE ? 1u : 0u) | ENET_MAC_PACKET_FILTER_PCF(pMACFilter->PassCtrlPkts) | ENET_MAC_PACKET_FILTER_DBF(pMACFilter->DisableBroadcast ? 1u : 0u) | ENET_MAC_PACKET_FILTER_PM(pMACFilter->PassAllMulticast ? 1u : 0u) | ENET_MAC_PACKET_FILTER_DAIF(pMACFilter->DAFilter == ENET_FILTER_INVERSE_ENABLE ? 1u : 0u) | ENET_MAC_PACKET_FILTER_HMC(pMACFilter->HashMulticast ? 1u : 0u) | ENET_MAC_PACKET_FILTER_HUC(pMACFilter->HashUnicast ? 1u : 0u) | ENET_MAC_PACKET_FILTER_PR(pMACFilter->PromiscuousMode ? 1u : 0u); ENET_HWA_MAC_SetPacketFilter(pEnetBase, u32FilterCtrl); } /** * @brief Set MAC filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pMACFilter MAC filter configurations */ void Enet_SetMACFilter(ENET_HandleType *pEnetHandle, const ENET_MACFilterType *pMACFilter) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_MACFILTER_SERVICE_ID)) { if (pMACFilter == NULL_PTR) { ENET_ReportDevError(ENET_SET_MACFILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (0u != Enet_AssertMACFilterConfiguration(pMACFilter)) { ENET_ReportDevError(ENET_SET_MACFILTER_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_MACFILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif Enet_MACFilterConfig(pEnetHandle->EnetBase, pMACFilter); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Get default layer3 layer4 filter configurations * @param[out] pL3L4Filter Default layer3 layer4 filter configurations */ void Enet_DefaultL3L4Filter(ENET_L3L4FilterType *pL3L4Filter) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (pL3L4Filter == NULL_PTR) { ENET_ReportDevError(ENET_DEFAULT_L3L4FILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { #endif pL3L4Filter->DMAChannelSelect = false; pL3L4Filter->DMAChannel = ENET_CHANNEL_0; pL3L4Filter->L4Protocol = ENET_MAC_LAYER_4_PROTOCOL_TCP; pL3L4Filter->DstPortFilter = ENET_FILTER_DISABLE; pL3L4Filter->SrcPortFilter = ENET_FILTER_DISABLE; pL3L4Filter->DstPort = 0u; pL3L4Filter->SrcPort = 0u; pL3L4Filter->L3Protocol = ENET_MAC_LAYER_3_PROTOCOL_IPV4; pL3L4Filter->DstIPFilter = ENET_FILTER_DISABLE; pL3L4Filter->SrcIPFilter = ENET_FILTER_DISABLE; pL3L4Filter->Ipv4DAMaskBit = 0u; pL3L4Filter->Ipv4SAMaskBit = 0u; pL3L4Filter->IPv4SrcAddr = 0u; pL3L4Filter->IPv4DstAddr = 0u; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Get current layer3 layer4 filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pFilterGroup Layer3 layer4 filter group * @param[in] pL3L4Filter Current layer3 layer4 filter configurations */ void Enet_GetL3L4Filter(const ENET_HandleType *pEnetHandle, ENET_MAC_L3L4FilterGroupType pFilterGroup, ENET_L3L4FilterType *pL3L4Filter) { bool bInverse; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_L3L4FILTER_SERVICE_ID)) { if (pL3L4Filter == NULL_PTR) { ENET_ReportDevError(ENET_GET_L3L4FILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if ((uint32_t)pFilterGroup >= (uint32_t)ENET_L3L4_FILTER_COUNT) { ENET_ReportDevError(ENET_GET_L3L4FILTER_SERVICE_ID, ENET_E_PARAM_GROUP); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_GET_L3L4FILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif pL3L4Filter->DMAChannelSelect = ENET_HWA_MAC_GetLayer3Layer4DMASelectEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->DMAChannel = (ENET_ChannelType)ENET_HWA_MAC_GetLayer3Layer4DMAChannel(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); bInverse = ENET_HWA_MAC_GetLayer4DestPortInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->DstPortFilter = ENET_HWA_MAC_GetLayer4DestPortMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup) ? (bInverse ? ENET_FILTER_INVERSE_ENABLE : ENET_FILTER_ENABLE) : ENET_FILTER_DISABLE; bInverse = ENET_HWA_MAC_GetLayer4SrcPortInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->SrcPortFilter = ENET_HWA_MAC_GetLayer4SrcPortMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup) ? (bInverse ? ENET_FILTER_INVERSE_ENABLE : ENET_FILTER_ENABLE) : ENET_FILTER_DISABLE; pL3L4Filter->L4Protocol = ENET_HWA_MAC_GetLayer4ProtocalType(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->DstPort = ENET_HWA_MAC_GetLayer4DestPort(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->SrcPort = ENET_HWA_MAC_GetLayer4SrcPort(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->L3Protocol = ENET_HWA_MAC_GetLayer3ProtocolType(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); bInverse = ENET_HWA_MAC_GetLayer3DestAddrInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->DstIPFilter = ENET_HWA_MAC_GetLayer3DestAddrMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup) ? (bInverse ? ENET_FILTER_INVERSE_ENABLE : ENET_FILTER_ENABLE) : ENET_FILTER_DISABLE; bInverse = ENET_HWA_MAC_GetLayer3SrcAddrInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->SrcIPFilter = ENET_HWA_MAC_GetLayer3SrcAddrMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup) ? (bInverse ? ENET_FILTER_INVERSE_ENABLE : ENET_FILTER_ENABLE) : ENET_FILTER_DISABLE; if (pL3L4Filter->L3Protocol == ENET_MAC_LAYER_3_PROTOCOL_IPV4) { pL3L4Filter->Ipv4DAMaskBit = ENET_HWA_MAC_GetLayer3IPv4DestAddrBitsMatch(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->Ipv4SAMaskBit = ENET_HWA_MAC_GetLayer3IPv4SrcAddrBitsMatch(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->IPv4DstAddr = ENET_HWA_MAC_GetLayer3DestIPv4Addr(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); pL3L4Filter->IPv4SrcAddr = ENET_HWA_MAC_GetLayer3SrcIPv4Addr(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); } else { pL3L4Filter->Ipv6MaskBit = ENET_HWA_MAC_GetLayer3IPv6AddrBitsMatch(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); ENET_HWA_MAC_GetLayer3IPv6Addr(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->IPv6Addr); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Set layer3 layer4 filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pFilterGroup Layer3 layer4 filter group * @param[in] pL3L4Filter Layer3 layer4 filter configurations */ void Enet_SetL3L4Filter(ENET_HandleType *pEnetHandle, ENET_MAC_L3L4FilterGroupType pFilterGroup, const ENET_L3L4FilterType *pL3L4Filter) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_L3L4FILTER_SERVICE_ID)) { if (pL3L4Filter == NULL_PTR) { ENET_ReportDevError(ENET_SET_L3L4FILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if ((uint32_t)pFilterGroup >= (uint32_t)ENET_L3L4_FILTER_COUNT) { ENET_ReportDevError(ENET_SET_L3L4FILTER_SERVICE_ID, ENET_E_PARAM_GROUP); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_L3L4FILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (0u != Enet_AssertL3L4FilterConfiguration(pEnetHandle, pL3L4Filter)) { ENET_ReportDevError(ENET_SET_L3L4FILTER_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif ENET_HWA_MAC_SetLayer3Layer4DMASelectEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->DMAChannelSelect); ENET_HWA_MAC_SetLayer3Layer4DMAChannel(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, (ENET_DMA_ChannelType)pL3L4Filter->DMAChannel); ENET_HWA_MAC_SetLayer4DestPortMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->DstPortFilter != ENET_FILTER_DISABLE); ENET_HWA_MAC_SetLayer4DestPortInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->DstPortFilter == ENET_FILTER_INVERSE_ENABLE); ENET_HWA_MAC_SetLayer4SrcPortMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->SrcPortFilter != ENET_FILTER_DISABLE); ENET_HWA_MAC_SetLayer4SrcPortInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->SrcPortFilter == ENET_FILTER_INVERSE_ENABLE); ENET_HWA_MAC_SetLayer4ProtocalType(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->L4Protocol); ENET_HWA_MAC_SetLayer4DestPort(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->DstPort); ENET_HWA_MAC_SetLayer4SrcPort(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->SrcPort); ENET_HWA_MAC_SetLayer3DestAddrMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->DstIPFilter != ENET_FILTER_DISABLE); ENET_HWA_MAC_SetLayer3DestAddrInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->DstIPFilter == ENET_FILTER_INVERSE_ENABLE); ENET_HWA_MAC_SetLayer3SrcAddrMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->SrcIPFilter != ENET_FILTER_DISABLE); ENET_HWA_MAC_SetLayer3SrcAddrInvMatchEnFlag(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->SrcIPFilter == ENET_FILTER_INVERSE_ENABLE); ENET_HWA_MAC_SetLayer3ProtocolType(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->L3Protocol); if (pL3L4Filter->L3Protocol == ENET_MAC_LAYER_3_PROTOCOL_IPV4) { ENET_HWA_MAC_SetLayer3IPv4DestAddrBitsMatch(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->Ipv4DAMaskBit); ENET_HWA_MAC_SetLayer3IPv4SrcAddrBitsMatch(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->Ipv4SAMaskBit); ENET_HWA_MAC_SetLayer3DestIPv4Addr(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->IPv4DstAddr); ENET_HWA_MAC_SetLayer3SrcIPv4Addr(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->IPv4SrcAddr); } else { ENET_HWA_MAC_SetLayer3IPv6AddrBitsMatch(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->Ipv6MaskBit); ENET_HWA_MAC_SetLayer3IPv6Addr(pEnetHandle->EnetBase, (uint8_t)pFilterGroup, pL3L4Filter->IPv6Addr); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif } /** * @brief Enable MAC layer3 layer4 filter * @param[in] pEnetHandle ENET driver handle * @param[in] bEnable true: enable layer3 layer4 filter, false: disable */ void Enet_EnableL3L4Filter(ENET_HandleType *pEnetHandle, bool bEnable) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_ENABLE_L3L4FILTER_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_ENABLE_L3L4FILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_SetLayer3Layer4FilterEnFlag(pEnetHandle->EnetBase, bEnable); ENET_HWA_MAC_SetIPChecksumOffloadEnFlag(pEnetHandle->EnetBase, bEnable); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief Get MAC VLAN filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pVlanFilterConfig MAC VLAN filter configurations */ void Enet_GetVlanFilterConfig(const ENET_HandleType *pEnetHandle, ENET_VlanFilterConfigType *pVlanFilterConfig) { bool u32Erivt, u32Ersvlm, u32Dovltc; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_VLANFILTER_CFG_SERVICE_ID)) { if (pVlanFilterConfig == NULL_PTR) { ENET_ReportDevError(ENET_GET_VLANFILTER_CFG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_GET_VLANFILTER_CFG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif pVlanFilterConfig->VlanFilterEnable = ENET_HWA_MAC_GetVLANTagFilterEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->InnerVlanRxStatus = ENET_HWA_MAC_GetRxStatusInnerVLANTagEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->OuterVlanRxStatus = ENET_HWA_MAC_GetRxStatusVLANTagEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->DoubleVlanEnable = ENET_HWA_MAC_GetDoubleVLANProcessEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->SVlanEnable = ENET_HWA_MAC_GetSVLANEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->VlanInverseMatch = ENET_HWA_MAC_GetVLANInverseMatchEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->HashFilterEnable = ENET_HWA_MAC_GetVLANTagHashTableMatchEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->HashCompareMode = (ENET_MAC_VLANCompareType)ENET_HWA_MAC_Get12BitVLANTagEnFlag(pEnetHandle->EnetBase); pVlanFilterConfig->InnerVlanStrip = ENET_HWA_MAC_GetInnerVLANTagStripMode(pEnetHandle->EnetBase); pVlanFilterConfig->OuterVlanStrip = ENET_HWA_MAC_GetVLANTagStripMode(pEnetHandle->EnetBase); u32Erivt = ENET_HWA_MAC_GetInnerVLANTagCmpEnFlag(pEnetHandle->EnetBase); u32Ersvlm = ENET_HWA_MAC_GetRxSVLANMatchEnFlag(pEnetHandle->EnetBase); u32Dovltc = ENET_HWA_MAC_GetVLANTypeCheckDisableFlag(pEnetHandle->EnetBase); if (u32Dovltc) { pVlanFilterConfig->HashFilterMode = u32Erivt ? ENET_VLAN_FILTER_INNER_ANYTYPE : ENET_VLAN_FILTER_OUTER_ANYTYPE; } else { if (u32Erivt) { pVlanFilterConfig->HashFilterMode = u32Ersvlm ? ENET_VLAN_FILTER_INNER_SVLAN : ENET_VLAN_FILTER_INNER_CVLAN; } else { pVlanFilterConfig->HashFilterMode = u32Ersvlm ? ENET_VLAN_FILTER_OUTER_SVLAN : ENET_VLAN_FILTER_OUTER_CVLAN; } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif } /** * @brief Enable MAC VLAN filter * @param[in] pEnetHandle ENET driver handle * @param[in] pVlanFilterConfig MAC VLAN filter configurations */ void Enet_EnableVlanFilter(ENET_HandleType *pEnetHandle, const ENET_VlanFilterConfigType *pVlanFilterConfig) { bool u32Erivt, u32Ersvlm, u32Dovltc; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_ENABLE_VLANFILTER_SERVICE_ID)) { if (pVlanFilterConfig == NULL_PTR) { ENET_ReportDevError(ENET_ENABLE_VLANFILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (0u != Enet_AssertVlanFilterConfiguration(pVlanFilterConfig)) { ENET_ReportDevError(ENET_ENABLE_VLANFILTER_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_ENABLE_VLANFILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_SetRxStatusInnerVLANTagEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->InnerVlanRxStatus); ENET_HWA_MAC_SetInnerVLANTagStripMode(pEnetHandle->EnetBase, pVlanFilterConfig->InnerVlanStrip); ENET_HWA_MAC_SetDoubleVLANProcessEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->DoubleVlanEnable); ENET_HWA_MAC_SetRxStatusVLANTagEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->OuterVlanRxStatus); ENET_HWA_MAC_SetVLANTagStripMode(pEnetHandle->EnetBase, pVlanFilterConfig->OuterVlanStrip); ENET_HWA_MAC_SetSVLANEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->SVlanEnable); ENET_HWA_MAC_SetVLANInverseMatchEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->VlanInverseMatch); ENET_HWA_MAC_SetVLANTagHashTableMatchEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->HashFilterEnable); ENET_HWA_MAC_Set12BitVLANTagEnFlag(pEnetHandle->EnetBase, (bool)pVlanFilterConfig->HashCompareMode); u32Erivt = ((pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_INNER_CVLAN) || (pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_INNER_SVLAN) || (pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_INNER_ANYTYPE)) ? true : false; u32Ersvlm = ((pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_OUTER_SVLAN) || (pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_INNER_SVLAN)) ? true : false; u32Dovltc = ((pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_OUTER_ANYTYPE) || (pVlanFilterConfig->HashFilterMode == ENET_VLAN_FILTER_INNER_ANYTYPE)) ? true : false; ENET_HWA_MAC_SetInnerVLANTagCmpEnFlag(pEnetHandle->EnetBase, u32Erivt); ENET_HWA_MAC_SetVLANTypeCheckDisableFlag(pEnetHandle->EnetBase, u32Dovltc); ENET_HWA_MAC_SetRxSVLANMatchEnFlag(pEnetHandle->EnetBase, u32Ersvlm); ENET_HWA_MAC_SetVLANTagFilterFilterEnFlag(pEnetHandle->EnetBase, pVlanFilterConfig->VlanFilterEnable); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Set vlan hash table * @param[in] pEnetHandle ENET driver handle * @param[in] bAddOrRemove true add to hash table,false remove from hash table * @param[in] u16VlanTag VLAN tag ID */ void Enet_SetVlanHashTable(ENET_HandleType *pEnetHandle, bool bAddOrRemove, uint16_t u16VlanTag) { uint32_t u32CrcVal, u32HashBit; uint8_t *pTag = (uint8_t *)&u16VlanTag; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_VLANHASH_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_VLANHASH_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (ENET_HWA_MAC_Get12BitVLANTagEnFlag(pEnetHandle->EnetBase)) { u32CrcVal = Enet_ComputeCRC(pTag, 12u); } else { u32CrcVal = Enet_ComputeCRC(pTag, 16u); } u32CrcVal = Enet_BitsReverse(u32CrcVal); u32HashBit = (u32CrcVal >> ENET_VLAN_HASH_TABLE_BIT_SHIFT) & ENET_VLAN_HASH_TABLE_BIT_MASK; if (bAddOrRemove) { pEnetHandle->EnetBase->MAC_VLAN_HASH_TABLE |= 1u << u32HashBit; } else { pEnetHandle->EnetBase->MAC_VLAN_HASH_TABLE &= ~(1u << u32HashBit); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief Poll wait VLAN perfect filter indirect registers operation complete * @param[in] pEnetBase ENET base address * @param[in] u32TryTimes Try times to read VLAN operation busy state * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Access to VLAN perfect filter indirect register is complete * @retval other values Access to VLAN perfect filter indirect register is failed */ static ENET_StatusType Enet_VlanCtrlBusyPollWait(const ENET_Type *pEnetBase, uint32_t u32TryTimes) { while (ENET_MAC_STATUS_BUSY == ENET_HWA_MAC_GetVLANOperationStatus(pEnetBase)) { if (--u32TryTimes == 0u) { break; } } return u32TryTimes > 0u ? ENET_STATUS_SUCCESS : ENET_STATUS_TIMEOUT; } /** * @brief Get current VLAN perfect filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pFilterGroup VLAN perfect filter group * @param[out] pPerfectFilter VLAN perfect filter configurations * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Get VLAN perfect filter configurations successfully * @retval other values Get VLAN perfect filter configurations failed */ ENET_StatusType Enet_GetVlanPerfectFilter(ENET_HandleType *pEnetHandle, ENET_MAC_VLANFilterGroupType pFilterGroup, ENET_VlanPerfectFilterType *pPerfectFilter) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; uint32_t u32VlanTagData, u32Erivt, u32Ersvlm, u32Dovltc, u32Temp; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_VLAN_PERFECTFILTER_SERVICE_ID)) { if (pPerfectFilter == NULL_PTR) { ENET_ReportDevError(ENET_GET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if ((uint32_t)pFilterGroup >= (uint32_t)ENET_VLAN_FILTER_COUNT) { ENET_ReportDevError(ENET_GET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_PARAM_GROUP); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_GET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_SetVLANTagFilterRegOffset(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); ENET_HWA_MAC_SetVLANCommandType(pEnetHandle->EnetBase, ENET_MAC_VLAN_COMMAND_READ); ENET_HWA_MAC_SetVLANOperationBusy(pEnetHandle->EnetBase); eStatus = Enet_VlanCtrlBusyPollWait(pEnetHandle->EnetBase, pEnetHandle->VlanOpBusyWait); if (ENET_STATUS_SUCCESS == eStatus) { u32VlanTagData = ENET_HWA_MAC_GetVLANTagData(pEnetHandle->EnetBase); pPerfectFilter->FilterGroupEnable = 0u != (u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_VEN_MASK); u32Temp = u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_ETV_MASK; pPerfectFilter->CompareMode = (ENET_MAC_VLANCompareType)u32Temp; pPerfectFilter->DMAChannelEnable = 0u != (u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_DMACHEN_MASK); u32Temp = (u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_DMACHN_MASK) >> ENET_MAC_VLAN_TAG_DATA_DMACHN_SHIFT; pPerfectFilter->DMAChannel = (ENET_ChannelType)u32Temp; pPerfectFilter->VlanTag = (uint16_t)((u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_VID_MASK) >> ENET_MAC_VLAN_TAG_DATA_VID_SHIFT); u32Erivt = u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_ERIVLT_MASK; u32Ersvlm = u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_ERSVLM_MASK; u32Dovltc = u32VlanTagData & ENET_MAC_VLAN_TAG_DATA_DOVLTC_MASK; if (u32Dovltc != 0u) { pPerfectFilter->FilterMode = (u32Erivt != 0u) ? ENET_VLAN_FILTER_INNER_ANYTYPE : ENET_VLAN_FILTER_OUTER_ANYTYPE; } else { if (u32Erivt != 0u) { pPerfectFilter->FilterMode = (u32Ersvlm != 0u) ? ENET_VLAN_FILTER_INNER_SVLAN : ENET_VLAN_FILTER_INNER_CVLAN; } else { pPerfectFilter->FilterMode = (u32Ersvlm != 0u) ? ENET_VLAN_FILTER_OUTER_SVLAN : ENET_VLAN_FILTER_OUTER_CVLAN; } } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Set VLAN perfect filter configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pFilterGroup VLAN perfect filter group * @param[in] pPerfectFilter VLAN perfect filter configurations * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Set VLAN perfect filter configurations successfully * @retval other values Set VLAN perfect filter configurations failed */ ENET_StatusType Enet_SetVlanPerfectFilter(ENET_HandleType *pEnetHandle, ENET_MAC_VLANFilterGroupType pFilterGroup, const ENET_VlanPerfectFilterType *pPerfectFilter) { uint32_t u32VlanTagData, u32Erivt, u32Ersvlm, u32Dovltc; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_VLAN_PERFECTFILTER_SERVICE_ID)) { if (pPerfectFilter == NULL_PTR) { ENET_ReportDevError(ENET_SET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if ((uint32_t)pFilterGroup >= (uint32_t)ENET_VLAN_FILTER_COUNT) { ENET_ReportDevError(ENET_SET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_PARAM_GROUP); } else { if (0u != Enet_AssertVlanPerfectFilterConfiguration(pPerfectFilter)) { ENET_ReportDevError(ENET_SET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_SET_VLAN_PERFECTFILTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif u32Erivt = ((pPerfectFilter->FilterMode == ENET_VLAN_FILTER_INNER_CVLAN) || (pPerfectFilter->FilterMode == ENET_VLAN_FILTER_INNER_SVLAN) || (pPerfectFilter->FilterMode == ENET_VLAN_FILTER_INNER_ANYTYPE)) ? 1u : 0u; u32Ersvlm = ((pPerfectFilter->FilterMode == ENET_VLAN_FILTER_OUTER_SVLAN) || (pPerfectFilter->FilterMode == ENET_VLAN_FILTER_INNER_SVLAN)) ? 1u : 0u; u32Dovltc = ((pPerfectFilter->FilterMode == ENET_VLAN_FILTER_OUTER_ANYTYPE) || (pPerfectFilter->FilterMode == ENET_VLAN_FILTER_INNER_ANYTYPE)) ? 1u : 0u; u32VlanTagData = ENET_MAC_VLAN_TAG_DATA_DMACHN(pPerfectFilter->DMAChannel) | ENET_MAC_VLAN_TAG_DATA_DMACHEN(pPerfectFilter->DMAChannelEnable ? 1u : 0u) | ENET_MAC_VLAN_TAG_DATA_ERIVLT(u32Erivt) | ENET_MAC_VLAN_TAG_DATA_ERSVLM(u32Ersvlm) | ENET_MAC_VLAN_TAG_DATA_DOVLTC(u32Dovltc) | ENET_MAC_VLAN_TAG_DATA_ETV(pPerfectFilter->CompareMode) | ENET_MAC_VLAN_TAG_DATA_VEN(pPerfectFilter->FilterGroupEnable ? 1u : 0u) | ENET_MAC_VLAN_TAG_DATA_VID(pPerfectFilter->VlanTag); ENET_HWA_MAC_SetVLANTagData(pEnetHandle->EnetBase, u32VlanTagData); ENET_HWA_MAC_SetVLANTagFilterRegOffset(pEnetHandle->EnetBase, (uint8_t)pFilterGroup); ENET_HWA_MAC_SetVLANCommandType(pEnetHandle->EnetBase, ENET_MAC_VLAN_COMMAND_WRITE); ENET_HWA_MAC_SetVLANOperationBusy(pEnetHandle->EnetBase); eStatus = Enet_VlanCtrlBusyPollWait(pEnetHandle->EnetBase, pEnetHandle->VlanOpBusyWait); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } /** * @brief Poll the busy bit in VLAN inclusion or replacement register * @param[in] pEnetBase ENET base address * @param[in] u32TryTimes Try times to read VLAN operation busy state * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS : Access to VLAN inclusion or replacement register is complete * @retval other values : Access to VLAN inclusion or replacement register is failed */ static ENET_StatusType Enet_VlanInclBusyPollWait(const ENET_Type *pEnetBase, uint32_t u32TryTimes) { while (ENET_MAC_STATUS_BUSY == ENET_HWA_MAC_GetVLANInclusionOperationStatus(pEnetBase)) { if (--u32TryTimes == 0u) { break; } } return u32TryTimes > 0u ? ENET_STATUS_SUCCESS : ENET_STATUS_TIMEOUT; } /** * @brief Write the indirect registers for channel based VLAN insertion * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel ENET DMA channel * @param[in] eVlanType VLAN type: C-VLAN or S-VLAN * @param[in] u16VlanTag VLAN tag value * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Write the indirect registers successfully * @retval other values Write the indirect registers failed */ static ENET_StatusType Enet_VlanInclWrite(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel, ENET_MAC_VLANType eVlanType, uint16_t u16VlanTag) { ENET_StatusType eStatus; /* Check busy state */ eStatus = Enet_VlanInclBusyPollWait(pEnetHandle->EnetBase, pEnetHandle->VlanOpBusyWait); if (ENET_STATUS_SUCCESS == eStatus) { ENET_HWA_MAC_SetVLANInclusionCommandType(pEnetHandle->EnetBase, ENET_MAC_VLAN_INCL_COMMAND_WRITE); ENET_HWA_MAC_SetVLANInclusionAddr(pEnetHandle->EnetBase, (uint8_t)eChannel); ENET_HWA_MAC_SetVLANType(pEnetHandle->EnetBase, eVlanType); ENET_HWA_MAC_SetTxVLANTag(pEnetHandle->EnetBase, u16VlanTag); /* Check busy state */ eStatus = Enet_VlanInclBusyPollWait(pEnetHandle->EnetBase, pEnetHandle->VlanOpBusyWait); } return eStatus; } /** * @brief Set outer VLAN insertion replacement or deletion * @param[in] pEnetHandle ENET driver handle * @param[in] pVlanConfig Outer VLAN operation parameters */ void Enet_SetTxOuterVlanConfig(ENET_HandleType *pEnetHandle, const ENET_TxVlanConfigType *pVlanConfig) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_TXOUTERVLAN_SERVICE_ID)) { if (pVlanConfig == NULL_PTR) { ENET_ReportDevError(ENET_SET_TXOUTERVLAN_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (((uint32_t)pVlanConfig->VlanCtrl > (uint32_t)ENET_MAC_VLAN_TAG_REPLACEMENT) || ((pVlanConfig->VlanType != ENET_MAC_VLAN_TYPE_C_VLAN) && (pVlanConfig->VlanType != ENET_MAC_VLAN_TYPE_S_VLAN))) { ENET_ReportDevError(ENET_SET_TXOUTERVLAN_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_TXOUTERVLAN_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (pVlanConfig->VlanType == ENET_MAC_VLAN_TYPE_S_VLAN) { ENET_HWA_MAC_SetSVLANEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } ENET_HWA_MAC_SetChannelBasedVLANTagInsertEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetVLANTagInputEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetVLANType(pEnetHandle->EnetBase, pVlanConfig->VlanType); ENET_HWA_MAC_SetVLANPriorityCtrlEnFlag(pEnetHandle->EnetBase, ENET_TRUE); ENET_HWA_MAC_SetTxVLANTag(pEnetHandle->EnetBase, pVlanConfig->VlanTag); ENET_HWA_MAC_SetVLANTagCtrlOperation(pEnetHandle->EnetBase, pVlanConfig->VlanCtrl); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Set outer VLAN channel based insertion * @param[in] pEnetHandle ENET driver handle * @param[in] pVlanConfig Outer VLAN channel based configurations * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS successful * @retval other values failed */ ENET_StatusType Enet_SetTxOuterVlanChannelBasedInsertion(ENET_HandleType *pEnetHandle, const ENET_OuterVlanCBTIType *pVlanConfig) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; uint8_t u8Channel; bool sVlanEnabled = ENET_FALSE; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_TXOUTVLAN_CBI_SERVICE_ID)) { if (pVlanConfig == NULL_PTR) { ENET_ReportDevError(ENET_SET_TXOUTVLAN_CBI_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_SET_TXOUTVLAN_CBI_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (0u != Enet_AssertVlanChannelBasedInsConfiguration(pEnetHandle, pVlanConfig)) { ENET_ReportDevError(ENET_SET_TXOUTVLAN_CBI_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif if (pVlanConfig->Enable) { ENET_HWA_MAC_SetChannelBasedVLANTagInsertEnFlag(pEnetHandle->EnetBase, ENET_TRUE); for (u8Channel = 0u; u8Channel < pEnetHandle->TxChannelCount; ++u8Channel) { eStatus = Enet_VlanInclWrite(pEnetHandle, (ENET_ChannelType)u8Channel, pVlanConfig->VlanType[u8Channel], pVlanConfig->VlanTag[u8Channel]); if (ENET_STATUS_SUCCESS != eStatus) { break; } if ((!sVlanEnabled) && (pVlanConfig->VlanType[u8Channel] == ENET_MAC_VLAN_TYPE_S_VLAN)) { sVlanEnabled = ENET_TRUE; ENET_HWA_MAC_SetSVLANEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } } if (ENET_STATUS_SUCCESS != eStatus) { ENET_HWA_MAC_SetChannelBasedVLANTagInsertEnFlag(pEnetHandle->EnetBase, ENET_FALSE); } } else { ENET_HWA_MAC_SetChannelBasedVLANTagInsertEnFlag(pEnetHandle->EnetBase, ENET_FALSE); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Set inner VLAN insertion replacement or deletion * @param[in] pEnetHandle ENET driver handle * @param[in] pVlanConfig Inner VLAN operation parameters */ void Enet_SetTxInnerVlanConfig(ENET_HandleType *pEnetHandle, const ENET_TxVlanConfigType *pVlanConfig) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_TXINNERVLAN_SERVICE_ID)) { if (pVlanConfig == NULL_PTR) { ENET_ReportDevError(ENET_SET_TXINNERVLAN_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (((uint32_t)pVlanConfig->VlanCtrl > (uint32_t)ENET_MAC_VLAN_TAG_REPLACEMENT) || ((pVlanConfig->VlanType != ENET_MAC_VLAN_TYPE_C_VLAN) && (pVlanConfig->VlanType != ENET_MAC_VLAN_TYPE_S_VLAN))) { ENET_ReportDevError(ENET_SET_TXINNERVLAN_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_TXINNERVLAN_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (pVlanConfig->VlanType == ENET_MAC_VLAN_TYPE_S_VLAN) { ENET_HWA_MAC_SetSVLANEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } ENET_HWA_MAC_SetDoubleVLANProcessEnFlag(pEnetHandle->EnetBase, ENET_TRUE); ENET_HWA_MAC_SetInnerVLANTagInputEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetInnerVLANType(pEnetHandle->EnetBase, pVlanConfig->VlanType); ENET_HWA_MAC_SetInnerVLANPriorityCtrlEnFlag(pEnetHandle->EnetBase, ENET_TRUE); ENET_HWA_MAC_SetTxInnerVLANTag(pEnetHandle->EnetBase, pVlanConfig->VlanTag); ENET_HWA_MAC_SetInnerVLANTagCtrl(pEnetHandle->EnetBase, pVlanConfig->VlanCtrl); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Register ENET system event callback function * @param[in] pEnetHandle ENET driver handle * @param[in] eCallback Callback function */ void Enet_RegisterSystemEventCallback(ENET_HandleType *pEnetHandle, ENET_EventCallbackType eCallback) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_REGISTER_SYSEVENT_SERVICE_ID)) { #endif pEnetHandle->EventCallback = eCallback; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Register receive frame callback function * @param[in] pEnetHandle ENET driver handle * @param[in] eCallback Callback function */ void Enet_RegisterRxCompleteCallback(ENET_HandleType *pEnetHandle, ENET_ChannelCallbackType eCallback) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_REGISTER_RXCOMP_SERVICE_ID)) { #endif pEnetHandle->RxReady = eCallback; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Register send frame complete callback function * @param[in] pEnetHandle ENET driver handle * @param[in] eCallback Callback function */ void Enet_RegisterTxCompleteCallback(ENET_HandleType *pEnetHandle, ENET_ChannelCallbackType eCallback) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_REGISTER_TXCOMP_SERVICE_ID)) { #endif pEnetHandle->TxComplete = eCallback; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Register wait send frame complete callback function * @param[in] pEnetHandle ENET driver handle * @param[in] eCallback Callback function */ void Enet_RegisterWaitTxCompleteCallback(ENET_HandleType *pEnetHandle, ENET_ChannelCallbackType eCallback) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_REGISTER_TXWAIT_SERVICE_ID)) { #endif pEnetHandle->TxCompleteWait = eCallback; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Get PTP default configuration * @param[out] pPTPConfig PTP default configurations */ void Enet_PTPDefaultConfig(Enet_PTPConfigType *pPTPConfig) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (pPTPConfig == NULL_PTR) { ENET_ReportDevError(ENET_PTP_DEFCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { #endif pPTPConfig->IncrementStep = 20u; pPTPConfig->OneStepMode = ENET_FALSE; pPTPConfig->Av8021ASMode = ENET_FALSE; pPTPConfig->TXTSSTSM = ENET_MAC_TX_TIMESTAMP_STATUS_MODE_PRESERVE; pPTPConfig->MacFilterForPtp = ENET_FALSE; pPTPConfig->SnapshotType = ENET_MAC_PTP_SNAPSHOT_FOR_E2E_EVENT; pPTPConfig->PtpLayer = ENET_MAC_PTP_OVER_IPV4; pPTPConfig->PtpVersion = ENET_MAC_PTP_IEEE_1588_V2; pPTPConfig->RolloverMode = ENET_MAC_TIMESTAMP_ROLLOVER_BINARY; pPTPConfig->TimeStampForAll = ENET_FALSE; pPTPConfig->PresentationTimeGen = ENET_FALSE; pPTPConfig->UpdateMethod = ENET_MAC_TIMESTAMP_UPDATE_FINE; pPTPConfig->ClkSource = ENET_MAC_PTP_CLK_SEL_PCC; #if ENET_SUPPORT_REFCLK_PIN pPTPConfig->RefClkPinInputFreq = 0U; #endif pPTPConfig->InitTime.Nanoseconds = 0u; pPTPConfig->InitTime.Seconds = 0u; pPTPConfig->InitTime.SecondsHi = 0u; pPTPConfig->IngressCorrection = 0u; pPTPConfig->EgressCorrection = 0u; #if (ENET_DEV_ERROR_REPORT == STD_ON) } #endif } /** * @brief Select the PTP source clock * @param[in] pEnet ENET instance base * @param[in] pPTPConfig PTP configurations * @return PTP source clock frequency */ static inline uint32_t Enet_PTPClockSourceConfig(ENET_Type *const pEnet, const Enet_PTPConfigType *pPTPConfig) { ENET_MAC_MiiModeType eMiiMode; ENET_MAC_SpeedType eSpeed; uint32_t u32Frequency; switch (pPTPConfig->ClkSource) { case ENET_MAC_PTP_CLK_SEL_PCC: ENET_HWA_Sysctrl_SetPTPClkSrc(ENET_MAC_PTP_CLK_SEL_PCC); u32Frequency = PCC_GetPccFunctionClock(PCC_CLK_ENET); break; case ENET_MAC_PTP_CLK_SEL_TX_CLK: ENET_HWA_Sysctrl_SetPTPClkSrc(ENET_MAC_PTP_CLK_SEL_TX_CLK); eMiiMode = ENET_HWA_MAC_GetPhyMiiMode(pEnet); if (eMiiMode == ENET_MAC_PHY_RGMII) { eSpeed = ENET_HWA_MAC_GetSpeed(pEnet); if (eSpeed == ENET_MAC_SPEED_1000MBPS) { u32Frequency = 125000000u; } else if (eSpeed == ENET_MAC_SPEED_100MBPS) { u32Frequency = 25000000u; } else { u32Frequency = 2500000u; } } if (eMiiMode == ENET_MAC_PHY_RMII) { u32Frequency = 50000000u; } else { u32Frequency = 25000000u; } break; #if ENET_SUPPORT_REFCLK_PIN case ENET_MAC_PTP_CLK_SEL_REFCLK_PIN: ENET_HWA_Sysctrl_SetPTPClkSrc(ENET_MAC_PTP_CLK_SEL_REFCLK_PIN); u32Frequency = pPTPConfig->RefClkPinInputFreq; break; #endif default: u32Frequency = 0u; break; } return u32Frequency; } /** * @brief Check the PTP clock and increment step valid * @param[in] pPTPConfig PTP default configurations * @param[in] u32ClkFreq PTP clock frequency * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS The PTP clock and increment step are valid * @retval ENET_STATUS_ERROR One of the PTP clock and increment step is invalid */ static ENET_StatusType Enet_CheckPTPClockStepValid(const Enet_PTPConfigType *pPTPConfig, uint32_t u32ClkFreq) { ENET_StatusType eStatus = ENET_STATUS_SUCCESS; uint32_t u32Tmp; int s32Sub; if (u32ClkFreq == 0u) { eStatus = ENET_STATUS_INVALID_PARAM; } else { u32Tmp = u32ClkFreq * (uint32_t)pPTPConfig->IncrementStep; if (pPTPConfig->UpdateMethod == ENET_MAC_TIMESTAMP_UPDATE_COARSE) { /* In coarse method the system clock increment is directly triggered by u32ClkFreq, * the u32ClkFreq * IncrementStep must be close to 1000000000 */ s32Sub = (int32_t)(u32Tmp - 1000000000u); if (s32Sub > 512 || s32Sub < -512) { eStatus = ENET_STATUS_ERROR; } } else { /* In fine method the system clock increment is triggered by clock divided from * u32ClkFreq, the u32ClkFreq * IncrementStep must be greater than 1000000000 */ if (u32Tmp < 1000000000u) { eStatus = ENET_STATUS_ERROR; } } } return eStatus; } /** * @brief Convert PTP register value to nanoseconds value * @param[in] u32Subseconds PTP subseconds register value * @return PTP nanoseconds value */ static inline uint32_t Enet_PTPRegValue2Nanoseconds(uint32_t u32Subseconds) { uint64_t u64Value = (uint64_t)u32Subseconds * (uint64_t)1000000000u; return (uint32_t)(u64Value >> 31u); } /** * @brief Convert nanoseconds value to PTP register value * @param[in] u32Nanoseconds PTP nanoseconds value * @return PTP subseconds register value */ static inline uint32_t Enet_PTPNanoseconds2RegValue(uint32_t u32Nanoseconds) { uint64_t u64Value = (uint64_t)u32Nanoseconds * (uint64_t)0x80000000u; return (uint32_t)(u64Value / (uint64_t)1000000000u); } /** * @brief Set PTP counter increment value * @param[in] pEnetHandle ENET driver handle * @param[in] pPTPConfig PTP configurations * @param[in] PtpClkFreq PTP reference clock source frequency * @note Attempt to set base Addend value close to 0x80000000u * Binary rollover mode : * IncrementValue * AddendValue = 2^31 * 2^32 / PtpClkFreq * IncrementValue = 2^31 * 2 / PtpClkFreq * * Digital rollover mode : * IncrementValue * AddendValue = 10^9 * 2^32 / PtpClkFreq * IncrementValue = 10^9 * 2 / PtpClkFreq */ static void Enet_PTPSetIncrementValue(ENET_HandleType *pEnetHandle, const Enet_PTPConfigType *pPTPConfig, uint32_t PtpClkFreq) { uint32_t u32IncValue; uint32_t u32Ssinc; uint64_t u64Temp; /* The fractional part of SUB_SECOND_INCREMENT register is ignored,which is compensated in AddendValue */ if (pPTPConfig->RolloverMode == ENET_MAC_TIMESTAMP_ROLLOVER_BINARY) { u64Temp = (uint64_t)0x80000000u * (uint64_t)pPTPConfig->IncrementStep + (uint64_t)500000000u; u32Ssinc = (uint32_t)(u64Temp / (uint64_t)1000000000u); pEnetHandle->PtpAddend = (uint32_t)(((uint64_t)0x80000000u * (uint64_t)0x100000000ull) / ((uint64_t)PtpClkFreq * (uint64_t)u32Ssinc)); } else { u32Ssinc = (uint32_t)pPTPConfig->IncrementStep; pEnetHandle->PtpAddend = (uint32_t)(((uint64_t)1000000000u * (uint64_t)0x100000000ull) / ((uint64_t)PtpClkFreq * (uint64_t)u32Ssinc)); } u32IncValue = ENET_MAC_SUB_SECOND_INCREMENT_SSINC(u32Ssinc) | ENET_MAC_SUB_SECOND_INCREMENT_SNSINC(0u); ENET_HWA_MAC_SetSubSecondIncrementReg(pEnetHandle->EnetBase, u32IncValue); } /** * @brief Poll wait PTP control register u32PollMask bit cleared * @param[in] pEnetBase ENET base address * @param[in] u32PollMask PTP control register mask bit * @param[in] u32Timeout Timeout counter * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS PTP control poll mask completed * @retval ENET_STATUS_TIMEOUT PTP control poll mask timeout */ static ENET_StatusType Enet_PTPCtrlPollWait(const ENET_Type *pEnetBase, uint32_t u32PollMask, uint32_t u32Timeout) { while (0u != (ENET_HWA_MAC_GetTimestampControl(pEnetBase) & u32PollMask)) { if (--u32Timeout == 0u) { break; } } return u32Timeout > 0u ? ENET_STATUS_SUCCESS : ENET_STATUS_TIMEOUT; } /** * @brief Initialize the PTP system time * @param[in] pEnetHandle ENET driver handle * @param[in] eRolloverMode PTP subseconds register rollover mode * @param[in] pTime The time to initialize * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Initialize PTP system time successfully * @retval other values Initialize PTP system time failed */ static inline ENET_StatusType Enet_PTPInitializeSystemTime(ENET_HandleType *pEnetHandle, ENET_MAC_TimestampRolloverType eRolloverMode, const ENET_TimestampType *pTime) { uint32_t u32NsValue; ENET_HWA_MAC_SetSystemTimeHigherWordSeconds(pEnetHandle->EnetBase, pTime->SecondsHi); ENET_HWA_MAC_SetSystemTimeSecondsUpdateValue(pEnetHandle->EnetBase, pTime->Seconds); u32NsValue = pTime->Nanoseconds; if (eRolloverMode == ENET_MAC_TIMESTAMP_ROLLOVER_BINARY) { u32NsValue = Enet_PTPNanoseconds2RegValue(u32NsValue); } ENET_HWA_MAC_SetSystemTimeNanoSecondsUpdateValue(pEnetHandle->EnetBase, u32NsValue); ENET_HWA_MAC_SetTimeUpdateOperation(pEnetHandle->EnetBase, ENET_MAC_SYSTEM_TIME_ADD_TIME); ENET_HWA_MAC_InitTimestamp(pEnetHandle->EnetBase); return Enet_PTPCtrlPollWait(pEnetHandle->EnetBase, ENET_MAC_TIMESTAMP_CONTROL_TSINIT_MASK, pEnetHandle->PtpPollWait); } /** * @brief Set PTP ingress synchronization correction value * @param[in] pEnetHandle ENET driver handle * @param[in] eRolloverMode PTP subseconds register rollover mode * @param[in] IngressCorrection The time stamp correction nanoseconds on the ingress path * @note MAC_Ingress_Timestamp_Latency + 2 times the clock-period of the PTP clock, * and the subnanoseconds is ignored */ static void Enet_PTPSetIngressSyncCorrection(ENET_HandleType *pEnetHandle, ENET_MAC_TimestampRolloverType eRolloverMode, uint32_t IngressCorrection) { uint32_t u32Regvalue; if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == eRolloverMode) { u32Regvalue = Enet_PTPNanoseconds2RegValue(IngressCorrection); u32Regvalue = (~u32Regvalue) + (uint32_t)1u; } else { u32Regvalue = (uint32_t)((uint32_t)1000000000u - IngressCorrection) | (uint32_t)0x80000000u; } ENET_HWA_MAC_SetTimestampIngressCorrectionInNanoseconds(pEnetHandle->EnetBase, (int32_t)u32Regvalue); ENET_HWA_MAC_SetTimestampIngressCorrectionInSubNanoseconds(pEnetHandle->EnetBase, (int8_t)0); } /** * @brief Set PTP egress synchronization correction value * @param[in] pEnetHandle ENET driver handle * @param[in] eRolloverMode PTP subseconds register rollover mode * @param[in] EgressCorrection The time stamp correction nanoseconds on the egress path * @note MAC_Egress_Timestamp_Latency + 2 times the clock-period of the PTP clock, * and the subnanoseconds is ignored */ static void Enet_PTPSetEgressSyncCorrection(ENET_HandleType *pEnetHandle, ENET_MAC_TimestampRolloverType eRolloverMode, uint32_t EgressCorrection) { uint32_t u32Regvalue; if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == eRolloverMode) { u32Regvalue = Enet_PTPNanoseconds2RegValue(EgressCorrection); } else { u32Regvalue = EgressCorrection; } ENET_HWA_MAC_SetTimestampEgressCorrectionInNanoseconds(pEnetHandle->EnetBase, (int32_t)u32Regvalue); ENET_HWA_MAC_SetTimestampEgressCorrectionInSubNanoseconds(pEnetHandle->EnetBase, (int8_t)0); } /** * @brief Start PTP counter process * @param[in] pEnetHandle ENET driver handle * @param[in] pPTPConfig PTP initialize configurations * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Start PTP successfully * @retval other values Start PTP failed */ ENET_StatusType Enet_PTPStart(ENET_HandleType *pEnetHandle, const Enet_PTPConfigType *pPTPConfig) { uint32_t u32RegValue; uint32_t PtpClkFreq; uint32_t u32PpsIndex; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_START_SERVICE_ID)) { if (pPTPConfig == NULL_PTR) { ENET_ReportDevError(ENET_PTP_START_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_START_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (0u != Enet_AssertPTPConfiguration(pPTPConfig)) { ENET_ReportDevError(ENET_PTP_START_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if ((pEnetHandle->PTPState != ENET_STATE_UNINIT) && (pEnetHandle->PTPState != ENET_STATE_STOPPED)) { eStatus = ENET_STATUS_ERROR; ENET_ReportDevError(ENET_PTP_START_SERVICE_ID, ENET_E_DRIVER_REPEAT_INIT); } else { #endif /* Disable timestamp interrupt */ ENET_HWA_MAC_SetTimestampInterruptEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetTimestampControl(pEnetHandle->EnetBase, 0x00002000u); /* Set ptp reference clock and get clock frequency */ PtpClkFreq = Enet_PTPClockSourceConfig(pEnetHandle->EnetBase, pPTPConfig); if (ENET_STATUS_SUCCESS == Enet_CheckPTPClockStepValid(pPTPConfig, PtpClkFreq)) { /* Enable timestamping */ ENET_HWA_MAC_SetTimestampEnFlag(pEnetHandle->EnetBase, true); /* Timestamping config */ ENET_HWA_MAC_SetAV802_1ASModeEnFlag(pEnetHandle->EnetBase, pPTPConfig->Av8021ASMode); ENET_HWA_MAC_SetTxTimestampStatusMode(pEnetHandle->EnetBase, pPTPConfig->TXTSSTSM); ENET_HWA_MAC_SetUseMACAddrForPTPPacketFilterEnFlag(pEnetHandle->EnetBase, pPTPConfig->MacFilterForPtp); u32RegValue = ENET_HWA_MAC_GetTimestampControl(pEnetHandle->EnetBase); u32RegValue &= ~(ENET_MAC_TIMESTAMP_CONTROL_SNAPTYPSEL_MASK | ENET_MAC_TIMESTAMP_CONTROL_TSMSTRENA_MASK | ENET_MAC_TIMESTAMP_CONTROL_TSEVNTENA_MASK | ENET_MAC_TIMESTAMP_CONTROL_TSIPV4ENA_MASK | ENET_MAC_TIMESTAMP_CONTROL_TSIPV6ENA_MASK | ENET_MAC_TIMESTAMP_CONTROL_TSIPENA_MASK); u32RegValue |= (uint32_t)pPTPConfig->SnapshotType | (uint32_t)pPTPConfig->PtpLayer; ENET_HWA_MAC_SetTimestampControl(pEnetHandle->EnetBase, u32RegValue); ENET_HWA_MAC_SetPTPPacketVersion(pEnetHandle->EnetBase, pPTPConfig->PtpVersion); ENET_HWA_MAC_SetIimestampRolloverCtrl(pEnetHandle->EnetBase, pPTPConfig->RolloverMode); ENET_HWA_MAC_SetTimestampForAllPacketEnFlag(pEnetHandle->EnetBase, pPTPConfig->TimeStampForAll); ENET_HWA_MAC_SetPresentationTimeGenerationEnFlag(pEnetHandle->EnetBase, pPTPConfig->PresentationTimeGen); ENET_HWA_MAC_SetTimestampUpdateMethod(pEnetHandle->EnetBase, pPTPConfig->UpdateMethod); Enet_PTPSetIncrementValue(pEnetHandle, pPTPConfig, PtpClkFreq); /* Initialize the Timestamp Addend register in fine update mode */ if (pPTPConfig->UpdateMethod == ENET_MAC_TIMESTAMP_UPDATE_FINE) { ENET_HWA_MAC_SetTimestampAddend(pEnetHandle->EnetBase, pEnetHandle->PtpAddend); ENET_HWA_MAC_UpdateAddendRegister(pEnetHandle->EnetBase); eStatus = Enet_PTPCtrlPollWait(pEnetHandle->EnetBase, ENET_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK, pEnetHandle->PtpPollWait); } if (ENET_STATUS_SUCCESS == eStatus) { Enet_PTPSetIngressSyncCorrection(pEnetHandle, pPTPConfig->RolloverMode, pPTPConfig->IngressCorrection); Enet_PTPSetEgressSyncCorrection(pEnetHandle, pPTPConfig->RolloverMode, pPTPConfig->EgressCorrection); /* Setting the initial time */ eStatus = Enet_PTPInitializeSystemTime(pEnetHandle, pPTPConfig->RolloverMode, &pPTPConfig->InitTime); if (ENET_STATUS_SUCCESS == eStatus) { for (u32PpsIndex = 0u; u32PpsIndex < ENET_PPS_CHANNEL_COUNT; ++u32PpsIndex) { pEnetHandle->PpsInterval[u32PpsIndex] = 0u; pEnetHandle->PpsWidth[u32PpsIndex] = 0u; } pEnetHandle->PTPState = ENET_STATE_READY; ENET_HWA_MAC_SetTimestampInterruptEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } } /* Disable timestamping function if an error occurs */ if (ENET_STATUS_SUCCESS != eStatus) { ENET_HWA_MAC_SetTimestampEnFlag(pEnetHandle->EnetBase, false); } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } /** * @brief Stop PTP counter process * @param[in] pEnetHandle ENET driver handle */ void Enet_PTPStop(ENET_HandleType *pEnetHandle) { uint32_t u32PpsIndex; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_STOP_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_PTP_STOP_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_SetTimestampInterruptEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetTimestampEnFlag(pEnetHandle->EnetBase, ENET_FALSE); for (u32PpsIndex = 0u; u32PpsIndex < ENET_PPS_CHANNEL_COUNT; ++u32PpsIndex) { pEnetHandle->PpsInterval[u32PpsIndex] = 0u; pEnetHandle->PpsWidth[u32PpsIndex] = 0u; } pEnetHandle->PTPState = ENET_STATE_STOPPED; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief Get PTP current system time * @param[in] pEnetHandle ENET driver handle * @param[out] pTime PTP system time * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Get PTP system time successfully * @retval other values Get PTP system time failed */ ENET_StatusType Enet_PTPGetTime(const ENET_HandleType *pEnetHandle, ENET_TimestampType *pTime) { uint32_t u32Seconds, u32Nanoseconds; uint16_t u16SecondsHi; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_GETTIME_SERVICE_ID)) { if (pTime == NULL_PTR) { ENET_ReportDevError(ENET_PTP_GETTIME_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_GETTIME_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (pEnetHandle->PTPState == ENET_STATE_READY) { pTime->SecondsHi = ENET_HWA_MAC_GetSystemTimeHigherWordSeconds(pEnetHandle->EnetBase); pTime->Seconds = ENET_HWA_MAC_GetSystemTimeSeconds(pEnetHandle->EnetBase); u32Nanoseconds = ENET_HWA_MAC_GetSystemTimeNanoSeconds(pEnetHandle->EnetBase); u32Seconds = ENET_HWA_MAC_GetSystemTimeSeconds(pEnetHandle->EnetBase); u16SecondsHi = ENET_HWA_MAC_GetSystemTimeHigherWordSeconds(pEnetHandle->EnetBase); if ((u32Seconds != pTime->Seconds) && (pTime->Nanoseconds < 500000000u)) { pTime->Seconds = u32Seconds; } if ((u16SecondsHi != pTime->SecondsHi) && (pTime->Seconds < 100u)) { pTime->SecondsHi = u16SecondsHi; } if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == ENET_HWA_MAC_GetTimestampRolloverCtrl(pEnetHandle->EnetBase)) { u32Nanoseconds = Enet_PTPRegValue2Nanoseconds(u32Nanoseconds); } pTime->Nanoseconds = u32Nanoseconds; eStatus = ENET_STATUS_SUCCESS; } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Set PTP system time * @param[in] pEnetHandle ENET driver handle * @param[in] pTime Time to set * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Set PTP time successfully * @retval other values Set PTP time failed */ ENET_StatusType Enet_PTPSetTime(ENET_HandleType *pEnetHandle, const ENET_TimestampType *pTime) { ENET_MAC_TimestampRolloverType eRolloverMode; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_SETTIME_SERVICE_ID)) { if (pTime == NULL_PTR) { ENET_ReportDevError(ENET_PTP_SETTIME_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_SETTIME_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (pEnetHandle->PTPState == ENET_STATE_READY) { eRolloverMode = ENET_HWA_MAC_GetTimestampRolloverCtrl(pEnetHandle->EnetBase); eStatus = Enet_PTPInitializeSystemTime(pEnetHandle, eRolloverMode, pTime); } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Update PTP system time offset * @param[in] pEnetHandle ENET driver handle * @param[in] pTime Time offset * @param[in] bSubtraction Subtract from PTP system time,or add to PTP system time * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Update PTP time successfully * @retval other values Update PTP time failed */ ENET_StatusType Enet_PTPUpdateTime(ENET_HandleType * pEnetHandle, const ENET_TimestampType *pTime, bool bSubtraction) { ENET_MAC_TimestampRolloverType eRolloverMode; uint32_t u32RegValue, u32Subns, u32Addend; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_UPDATETIME_SERVICE_ID)) { if (pTime == NULL_PTR) { ENET_ReportDevError(ENET_PTP_UPDATETIME_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pTime->SecondsHi != 0u) { ENET_ReportDevError(ENET_PTP_UPDATETIME_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_UPDATETIME_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (pEnetHandle->PTPState == ENET_STATE_READY) { u32Subns = pTime->Nanoseconds; u32Addend = ENET_HWA_MAC_GetTimestampAddend(pEnetHandle->EnetBase); eRolloverMode = ENET_HWA_MAC_GetTimestampRolloverCtrl(pEnetHandle->EnetBase); if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == eRolloverMode) { u32Subns = Enet_PTPNanoseconds2RegValue(u32Subns); } if (bSubtraction) { ENET_HWA_MAC_SetTimeUpdateOperation(pEnetHandle->EnetBase, ENET_MAC_SYSTEM_TIME_SUBTRACT_TIME); u32RegValue = pTime->Seconds != 0u ? (0xFFFFFFFFu - (pTime->Seconds - 1u)) : 0u; ENET_HWA_MAC_SetSystemTimeSecondsUpdateValue(pEnetHandle->EnetBase, u32RegValue); if (u32Subns != 0u) { u32RegValue = (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == eRolloverMode) ? (0x80000000u - u32Subns) : (1000000000u - u32Subns); } else { u32RegValue = 0u; } ENET_HWA_MAC_SetSystemTimeNanoSecondsUpdateValue(pEnetHandle->EnetBase, u32RegValue); } else { ENET_HWA_MAC_SetTimeUpdateOperation(pEnetHandle->EnetBase, ENET_MAC_SYSTEM_TIME_ADD_TIME); ENET_HWA_MAC_SetSystemTimeSecondsUpdateValue(pEnetHandle->EnetBase, pTime->Seconds); ENET_HWA_MAC_SetSystemTimeNanoSecondsUpdateValue(pEnetHandle->EnetBase, u32Subns); } ENET_HWA_MAC_UpdateTimestamp(pEnetHandle->EnetBase); Enet_PTPCtrlPollWait(pEnetHandle->EnetBase, ENET_MAC_TIMESTAMP_CONTROL_TSUPDT_MASK, pEnetHandle->PtpPollWait); if (ENET_STATUS_SUCCESS == eStatus) { ENET_HWA_MAC_SetTimestampAddend(pEnetHandle->EnetBase, u32Addend); ENET_HWA_MAC_UpdateAddendRegister(pEnetHandle->EnetBase); Enet_PTPCtrlPollWait(pEnetHandle->EnetBase, ENET_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK, pEnetHandle->PtpPollWait); } } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Adjust the PTP counter frequency * @param[in] pEnetHandle ENET driver handle * @param[in] PPb PTP frequency bias in PPB * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Adjust PTP frequency successfully * @retval ENET_STATUS_INVALID_PARAM Parameter invalid * @retval ENET_STATUS_UNSUPPORTED Time stamp update mode unsupported * @retval ENET_STATUS_NOT_READY Time stamp not ready */ ENET_StatusType Enet_PTPAdjustFrequency(ENET_HandleType *pEnetHandle, int PPb) { uint64_t u64Addend; int s32Temp; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_ADJUST_FREQ_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_ADJUST_FREQ_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else if ((PPb > 1024000) || (PPb < -1024000)) { ENET_ReportDevError(ENET_PTP_ADJUST_FREQ_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif if (pEnetHandle->PTPState == ENET_STATE_READY) { if (ENET_MAC_TIMESTAMP_UPDATE_FINE == ENET_HWA_MAC_GetTimestampUpdateMethod(pEnetHandle->EnetBase)) { s32Temp = (int)1000000000 - PPb; u64Addend = ((uint64_t)pEnetHandle->PtpAddend * (uint64_t)1000000000u) / (uint32_t)s32Temp; ENET_HWA_MAC_SetTimestampAddend(pEnetHandle->EnetBase, (uint32_t)u64Addend); ENET_HWA_MAC_UpdateAddendRegister(pEnetHandle->EnetBase); Enet_PTPCtrlPollWait(pEnetHandle->EnetBase, ENET_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK, pEnetHandle->PtpPollWait); } else { eStatus = ENET_STATUS_UNSUPPORTED; } } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif return eStatus; } /** * @brief Enable PTP channel PPS out in fixed mode * @param[in] pEnetHandle ENET driver handle * @param[in] ePPSChannel PTP PPS channel * @param[in] eFreqCtrl PTP fixed PPS out frequency control * In binary rollover mode: PPS frequency = 2^eFreqCtrl * In digital rollover mode: PPS frequency = (eFreqCtrl == 0) ? 1 : 2^(eFreqCtrl - 1) * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Enable PTP channel PPS out successfully * @retval other values Enable PTP channel PPS out failed */ ENET_StatusType Enet_PTPFixedPPSOut(ENET_HandleType *pEnetHandle, ENET_MAC_PPSChannelType ePPSChannel, ENET_MAC_PPSFreqCtrlType eFreqCtrl) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_FIXED_PPSOUT_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_FIXED_PPSOUT_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if ((uint32_t)ePPSChannel >= (uint32_t)ENET_PPS_CHANNEL_COUNT) { ENET_ReportDevError(ENET_PTP_FIXED_PPSOUT_SERVICE_ID, ENET_E_PARAM_PPSCHANNEL); } else { if ((uint32_t)eFreqCtrl > (uint32_t)ENET_MAC_PPS_BINARY_32768HZ_DIGITAL_16384HZ) { ENET_ReportDevError(ENET_PTP_FIXED_PPSOUT_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif if (pEnetHandle->PTPState == ENET_STATE_READY) { ENET_HWA_MAC_SetChannelFlexiblePPSOutputEnFlag(pEnetHandle->EnetBase, ENET_FALSE); ENET_HWA_MAC_SetFixedPPSOutputFrequency(pEnetHandle->EnetBase, eFreqCtrl); if (ENET_PTP_PPS_DIR_OUTPUT != ENET_HWA_Sysctrl_GetPPSPinDirection(ePPSChannel)) { ENET_HWA_Sysctrl_SetPPSPinDirection(ePPSChannel, ENET_PTP_PPS_DIR_OUTPUT); } eStatus = ENET_STATUS_SUCCESS; } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif return eStatus; } /** * @brief Calculate flexible PPS out pulse interval and width * @param[in] pEnetHandle ENET driver handle * @param[in] eRolloverMode Roll over mode * @param[out] pInterval PTP flexible PPS out pulse interval * @param[out] pWidth PTP flexible PPS out pulse width * @note * Interval register value = (Interval nanoseconds value / MAC_Sub_Second_Increment) - 1 * Width register value = (Width nanoseconds value / MAC_Sub_Second_Increment) - 1 */ static void Enet_CalculatePPSIntervalWidth(ENET_HandleType *pEnetHandle, ENET_MAC_PPSChannelType ePPSChannel, ENET_MAC_TimestampRolloverType eRolloverMode, uint32_t *pInterval, uint32_t *pWidth) { uint32_t u32IncValue, u32Interval, u32Width; u32IncValue = pEnetHandle->EnetBase->MAC_SUB_SECOND_INCREMENT; u32IncValue = ((u32IncValue & ENET_MAC_SUB_SECOND_INCREMENT_SSINC_MASK) >> ENET_MAC_SUB_SECOND_INCREMENT_SSINC_SHIFT) * 256u + ((u32IncValue & ENET_MAC_SUB_SECOND_INCREMENT_SNSINC_MASK) >> ENET_MAC_SUB_SECOND_INCREMENT_SNSINC_SHIFT); if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == eRolloverMode) { u32IncValue = Enet_PTPRegValue2Nanoseconds(u32IncValue); } if (pInterval != NULL_PTR) { u32Interval = pEnetHandle->PpsInterval[(uint8_t)ePPSChannel] / u32IncValue * 256u; *pInterval = u32Interval > 0u ? u32Interval - 1u : 0u; } if (pWidth != NULL_PTR) { u32Width = pEnetHandle->PpsWidth[(uint8_t)ePPSChannel] / u32IncValue * 256u; *pWidth = u32Width > 0u ? u32Width - 1u : 0u; } } /** * @brief Set PTP PPS channel target time * @param[in] pEnetHandle ENET driver handle * @param[in] ePPSChannel PTP PPS channel * @param[in] eRolloverMode PTP subseconds register rollover mode * @param[in] pTime PTP target time value , SecondsHi is ignored * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Set PTP target time successfully * @retval other values Set PTP target time failed */ static ENET_StatusType Enet_PTPSetTargetTime(ENET_HandleType *pEnetHandle, ENET_MAC_PPSChannelType ePPSChannel, ENET_MAC_TimestampRolloverType eRolloverMode, const ENET_TimestampType *pTime) { uint32_t u32RegValue; uint32_t u32Timeout = pEnetHandle->PtpPollWait; ENET_StatusType eStatus = ENET_STATUS_SUCCESS; ENET_MAC_StatusType eBusy; do { if (--u32Timeout == 0u) { eStatus = ENET_STATUS_ERROR; break; } eBusy = ENET_HWA_MAC_GetPPSTargetTimeBusyStatus(pEnetHandle->EnetBase, ePPSChannel); } while (eBusy == ENET_MAC_STATUS_BUSY); if (ENET_STATUS_SUCCESS == eStatus) { if (ENET_MAC_TIMESTAMP_ROLLOVER_BINARY == eRolloverMode) { u32RegValue = Enet_PTPNanoseconds2RegValue(pTime->Nanoseconds); } else { u32RegValue = pTime->Nanoseconds; } ENET_HWA_MAC_SetPPSTargetTimeInSeconds(pEnetHandle->EnetBase, ePPSChannel, pTime->Seconds); ENET_HWA_MAC_SetPPSTargetTimeInNanoseconds(pEnetHandle->EnetBase, ePPSChannel, u32RegValue); } return eStatus; } /** * @brief Enable PTP channel PPS out in flexible mode * @param[in] pEnetHandle ENET driver handle * @param[in] ePPSChannel PTP PPS channel * @param[in] PPSConfig PTP flexible PPS out configuration * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Enable PTP flexible PPS out successfully * @retval other values Enable PTP flexible PPS out failed * @note The Enet_PTPSetTime API may be called by application before target time reached, * in this case,the target time reached interrupt will not be triggered, * so users need to use some method to handle this event ,such as a timeout mechanism. */ ENET_StatusType Enet_PTPFlexiblePPSOut(ENET_HandleType *pEnetHandle, ENET_MAC_PPSChannelType ePPSChannel, const ENET_FlexPPSConfigType *PPSConfig) { uint32_t u32Interval, u32Width; ENET_MAC_TimestampRolloverType eRolloverMode; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PTP_FLEXIBLE_PPSOUT_SERVICE_ID)) { if (PPSConfig == NULL_PTR) { ENET_ReportDevError(ENET_PTP_FLEXIBLE_PPSOUT_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PTP_FLEXIBLE_PPSOUT_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if ((uint32_t)ePPSChannel >= (uint32_t)ENET_PPS_CHANNEL_COUNT) { ENET_ReportDevError(ENET_PTP_FLEXIBLE_PPSOUT_SERVICE_ID, ENET_E_PARAM_PPSCHANNEL); } else { if ((uint32_t)PPSConfig->Cmd > (uint32_t)ENET_MAC_PPS_CANCEL_STOP_PULSE_TRAIN) { ENET_ReportDevError(ENET_PTP_FLEXIBLE_PPSOUT_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif if (pEnetHandle->PTPState == ENET_STATE_READY) { eRolloverMode = ENET_HWA_MAC_GetTimestampRolloverCtrl(pEnetHandle->EnetBase); switch (PPSConfig->Cmd) { case ENET_MAC_PPS_START_SINGLE_PULSE: eStatus = Enet_PTPSetTargetTime(pEnetHandle, ePPSChannel, eRolloverMode, &PPSConfig->TargetTime); if (ENET_STATUS_SUCCESS == eStatus) { if (pEnetHandle->PpsWidth[(uint8_t)ePPSChannel] != PPSConfig->PPSWidth) { pEnetHandle->PpsWidth[(uint8_t)ePPSChannel] = PPSConfig->PPSWidth; Enet_CalculatePPSIntervalWidth(pEnetHandle, ePPSChannel, eRolloverMode, NULL_PTR, &u32Width); ENET_HWA_MAC_SetPPSWidth(pEnetHandle->EnetBase, ePPSChannel, u32Width); } } break; case ENET_MAC_PPS_START_PULSE_TRAIN: eStatus = Enet_PTPSetTargetTime(pEnetHandle, ePPSChannel, eRolloverMode, &PPSConfig->TargetTime); if (ENET_STATUS_SUCCESS == eStatus) { if ((pEnetHandle->PpsInterval[(uint8_t)ePPSChannel] != PPSConfig->PPSInterval) || (pEnetHandle->PpsWidth[(uint8_t)ePPSChannel] != PPSConfig->PPSWidth)) { pEnetHandle->PpsInterval[(uint8_t)ePPSChannel] = PPSConfig->PPSInterval; pEnetHandle->PpsWidth[(uint8_t)ePPSChannel] = PPSConfig->PPSWidth; Enet_CalculatePPSIntervalWidth(pEnetHandle, ePPSChannel, eRolloverMode, &u32Interval, &u32Width); ENET_HWA_MAC_SetPPSInterval(pEnetHandle->EnetBase, ePPSChannel, u32Interval); ENET_HWA_MAC_SetPPSWidth(pEnetHandle->EnetBase, ePPSChannel, u32Width); } } break; default: break; } if (ENET_STATUS_SUCCESS == eStatus) { ENET_HWA_MAC_SetChannelPPSTargetTimeModeSelect(pEnetHandle->EnetBase, ePPSChannel, ENET_MAC_PPS_TARGET_TIME_INT_ST); ENET_HWA_MAC_SetFlexiblePPSCommand(pEnetHandle->EnetBase, ePPSChannel, PPSConfig->Cmd); if (ENET_PTP_PPS_DIR_OUTPUT != ENET_HWA_Sysctrl_GetPPSPinDirection(ePPSChannel)) { ENET_HWA_Sysctrl_SetPPSPinDirection(ePPSChannel, ENET_PTP_PPS_DIR_OUTPUT); } } } else { eStatus = ENET_STATUS_NOT_READY; } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK /** * @brief Get EST configurations * @param[in] pEnetHandle ENET driver handle * @param[out] pEstConfig Structure to save configurations * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Get EST configurations successfully * @retval other values Get EST configurations failed */ ENET_StatusType Enet_TSN_GetEstConfig(ENET_HandleType *pEnetHandle, ENET_EstConfigType *pEstConfig) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_ESTCONFIG_SERVICE_ID)) { if (pEstConfig == NULL_PTR) { ENET_ReportDevError(ENET_GET_ESTCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_GET_ESTCONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif pEstConfig->PtpTimeOffset = ENET_HWA_MTL_GetEstPtpTimeOffset(pEnetHandle->EnetBase); pEstConfig->CurrentTimeOffset = ENET_HWA_MTL_GetEstCurrentTimeOffset(pEnetHandle->EnetBase); pEstConfig->IntervalLeftShift = ENET_HWA_MTL_GetEstTimeIntervalLeftShift(pEnetHandle->EnetBase); pEstConfig->SchedErrLoopCount = ENET_HWA_MTL_GetEstScheduleErrorLoopCount(pEnetHandle->EnetBase); pEstConfig->DropSchedErrFrame = ENET_HWA_MTL_GetDropSchedulingErrorFramesEnFlag(pEnetHandle->EnetBase); pEstConfig->NotDropFrameSizeErr = ENET_HWA_MTL_GetDropFrameSizeErrorFramesDisableFlag(pEnetHandle->EnetBase); pEstConfig->Overhead = ENET_HWA_MTL_GetEstOverheadBytes(pEnetHandle->EnetBase); eStatus = ENET_STATUS_SUCCESS; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Set EST configurations * @param[in] pEnetHandle ENET driver handle * @param[in] pEstConfig EST configurations * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Set EST configurations successfully * @retval other values Set EST configurations failed */ ENET_StatusType Enet_TSN_EstConfig(ENET_HandleType *pEnetHandle, const ENET_EstConfigType *pEstConfig) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_EST_CONFIG_SERVICE_ID)) { if (pEstConfig == NULL_PTR) { ENET_ReportDevError(ENET_EST_CONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (0u != Enet_AssertEstConfiguration(pEstConfig)) { ENET_ReportDevError(ENET_EST_CONFIG_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_EST_CONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (pEnetHandle->TxChannelCount < 2u) { ENET_ReportDevError(ENET_EST_CONFIG_SERVICE_ID, ENET_E_PARAM_TXCHANNEL); } else { #endif ENET_HWA_MTL_SetEstPtpTimeOffset(pEnetHandle->EnetBase, (uint8_t)pEstConfig->PtpTimeOffset); ENET_HWA_MTL_SetEstCurrentTimeOffset(pEnetHandle->EnetBase, pEstConfig->CurrentTimeOffset); ENET_HWA_MTL_SetEstTimeIntervalLeftShift(pEnetHandle->EnetBase, pEstConfig->IntervalLeftShift); ENET_HWA_MTL_SetEstScheduleErrorLoopCount(pEnetHandle->EnetBase, pEstConfig->SchedErrLoopCount); ENET_HWA_MTL_SetDropSchedulingErrorFramesEnFlag(pEnetHandle->EnetBase, pEstConfig->DropSchedErrFrame); ENET_HWA_MTL_SetDropFrameSizeErrorFramesDisableFlag(pEnetHandle->EnetBase, pEstConfig->NotDropFrameSizeErr); ENET_HWA_MTL_SetEstOverheadBytes(pEnetHandle->EnetBase, pEstConfig->Overhead); eStatus = ENET_STATUS_SUCCESS; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } /** * @brief Enable EST processing * @param[in] pEnetHandle ENET driver handle * @param[in] bEnable Enable or disable * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Enable EST function successfully * @retval other values Enable EST function failed */ ENET_StatusType Enet_TSN_EstEnable(ENET_HandleType *pEnetHandle, bool bEnable) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_EST_ENABLE_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_EST_ENABLE_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (pEnetHandle->TxChannelCount < 2u) { ENET_ReportDevError(ENET_EST_ENABLE_SERVICE_ID, ENET_E_PARAM_TXCHANNEL); } else { #endif ENET_HWA_MTL_SetEstEnableFlag(pEnetHandle->EnetBase, bEnable); eStatus = ENET_STATUS_SUCCESS; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Read gate control list data * @param[in] pEnetHandle ENET driver handle * @param[in] bGcrr Enables or disables gate control related registers * @param[in] u8Address GCL items address * @param[out] pData Pointer to GCL data * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Read GCL data successfully * @retval ENET_STATUS_TIMEOUT Read GCL data failed */ static ENET_StatusType Enet_GclRead(ENET_HandleType *pEnetHandle, bool bGcrr, uint8_t u8Address, uint32_t *pData) { ENET_StatusType eStatus = ENET_STATUS_SUCCESS; uint32_t u32Timeout = pEnetHandle->GclBusyWait; ENET_HWA_MTL_SetEstGateControlListAddress(pEnetHandle->EnetBase, u8Address); ENET_HWA_MTL_SetGateControlReleatedRegistersEnFlag(pEnetHandle->EnetBase, bGcrr); ENET_HWA_MTL_SetGclOperation(pEnetHandle->EnetBase, ENET_MTL_GCL_READ); ENET_HWA_MTL_SetGclOperationStartFlag(pEnetHandle->EnetBase, true); do { if (--u32Timeout == 0U) { eStatus = ENET_STATUS_TIMEOUT; break; } } while (ENET_HWA_MTL_GetGclOperationBusyState(pEnetHandle->EnetBase)); if (ENET_STATUS_SUCCESS == eStatus) { *pData = ENET_HWA_MTL_GetGclData(pEnetHandle->EnetBase); } return eStatus; } /** * @brief Write gate control list data * @param[in] pEnet ENET instance base * @param[in] bGcrr Enables or disables gate control related registers * @param[in] eAddress GCL items address * @param[in] eData GCL data * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Write GCL data successfully * @retval ENET_STATUS_TIMEOUT Write GCL data failed */ static ENET_StatusType Enet_GclWrite(ENET_HandleType *pEnetHandle, bool bGcrr, uint8_t u8Address, uint32_t u32Data) { ENET_StatusType eStatus = ENET_STATUS_SUCCESS; uint32_t u32Timeout = pEnetHandle->GclBusyWait; ENET_HWA_MTL_SetGclData(pEnetHandle->EnetBase, u32Data); ENET_HWA_MTL_SetEstGateControlListAddress(pEnetHandle->EnetBase, u8Address); ENET_HWA_MTL_SetGateControlReleatedRegistersEnFlag(pEnetHandle->EnetBase, bGcrr); ENET_HWA_MTL_SetGclOperation(pEnetHandle->EnetBase, ENET_MTL_GCL_WRITE); ENET_HWA_MTL_SetGclOperationStartFlag(pEnetHandle->EnetBase, true); do { if (--u32Timeout == 0U) { eStatus = ENET_STATUS_TIMEOUT; break; } } while (ENET_HWA_MTL_GetGclOperationBusyState(pEnetHandle->EnetBase)); return eStatus; } /** * @brief Read the current gate control list * @param[in] pEnetHandle ENET driver handle * @param[out] pGatelist Gate control list * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Read GCL successfully * @retval other values Read GCL failed */ ENET_StatusType Enet_TSN_GetEstGclConfig(ENET_HandleType *pEnetHandle, ENET_GateCtrlListType *pGatelist) { uint32_t u32Channel, u32Index, u32Value; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_EST_GETGCLCONFIG_SERVICE_ID)) { if (pGatelist == NULL_PTR) { ENET_ReportDevError(ENET_EST_GETGCLCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_EST_GETGCLCONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif eStatus = Enet_GclRead(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_BTR_LOW, &pGatelist->BaseTimeS); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclRead(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_BTR_HIGH, &pGatelist->BaseTimeNs); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclRead(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_CTR_LOW, &u32Value); if (ENET_STATUS_SUCCESS == eStatus) { pGatelist->CycleTimeS = (uint8_t)u32Value; eStatus = Enet_GclRead(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_CTR_HIGH, &pGatelist->CycleTimeNs); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclRead(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_TER, &pGatelist->TimeExtension); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclRead(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_LLR, &u32Value); if (ENET_STATUS_SUCCESS == eStatus) { pGatelist->GclLength = (uint16_t)u32Value; for (u32Index = 0U; u32Index < (uint32_t)pGatelist->GclLength; ++u32Index) { eStatus = Enet_GclRead(pEnetHandle, false, (uint8_t)u32Index, &u32Value); if (ENET_STATUS_SUCCESS != eStatus) { break; } pGatelist->Gate[u32Index].TimeInterval = u32Value & ((1u << ENET_TSN_GCL_INTERVAL_WIDTH_BITS) - 1u); for (u32Channel = 0U; u32Channel < pEnetHandle->TxChannelCount; ++u32Channel) { pGatelist->Gate[u32Index].GateOpen[u32Channel] = (u32Value & (1u << (ENET_TSN_GCL_INTERVAL_WIDTH_BITS + u32Channel))) ? ENET_TRUE : ENET_FALSE; } } } } } } } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return eStatus; } /** * @brief Install new gate control list * @param[in] pEnetHandle ENET driver handle * @param[in] pGatelist The Gate control list information * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Install new GCL successfully * @retval other values Install new GCL failed */ ENET_StatusType Enet_TSN_EstGclConfig(ENET_HandleType *pEnetHandle, const ENET_GateCtrlListType *pGatelist) { uint32_t u32Channel, u32Index, u32Value; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; uint32_t u32Timeout = pEnetHandle->GclBusyWait; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_EST_GCLCONFIG_SERVICE_ID)) { if (pGatelist == NULL_PTR) { ENET_ReportDevError(ENET_EST_GCLCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (0u != Enet_AssertGclConfiguration(pGatelist)) { ENET_ReportDevError(ENET_EST_GCLCONFIG_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_EST_GCLCONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (pEnetHandle->TxChannelCount < 2u) { ENET_ReportDevError(ENET_EST_GCLCONFIG_SERVICE_ID, ENET_E_PARAM_TXCHANNEL); } else { #endif for (u32Index = 0U; u32Index < (uint32_t)pGatelist->GclLength; ++u32Index) { u32Value = pGatelist->Gate[u32Index].TimeInterval & ((1u << ENET_TSN_GCL_INTERVAL_WIDTH_BITS) - 1u); for (u32Channel = 0U; u32Channel < pEnetHandle->TxChannelCount; ++u32Channel) { if (ENET_TRUE == pGatelist->Gate[u32Index].GateOpen[u32Channel]) { u32Value |= 1u << (ENET_TSN_GCL_INTERVAL_WIDTH_BITS + u32Channel); } } eStatus = Enet_GclWrite(pEnetHandle, false, (uint8_t)u32Index, u32Value); if (ENET_STATUS_SUCCESS != eStatus) { break; } } if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclWrite(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_BTR_LOW, pGatelist->BaseTimeS); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclWrite(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_BTR_HIGH, pGatelist->BaseTimeNs); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclWrite(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_CTR_LOW, pGatelist->CycleTimeS); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclWrite(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_CTR_HIGH, pGatelist->CycleTimeNs); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclWrite(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_TER, pGatelist->TimeExtension); if (ENET_STATUS_SUCCESS == eStatus) { eStatus = Enet_GclWrite(pEnetHandle, true, (uint8_t)ENET_MTL_GCL_LLR, pGatelist->GclLength); if (ENET_STATUS_SUCCESS == eStatus) { ENET_HWA_MTL_SetSwitchGateControlListEnFlag(pEnetHandle->EnetBase, true); while (!ENET_HWA_MTL_GetSwitchGateControlListCompleteFlag(pEnetHandle->EnetBase)) { if (--u32Timeout == 0u) { eStatus = ENET_STATUS_TIMEOUT; break; } } if (ENET_STATUS_SUCCESS == eStatus) { ENET_HWA_MTL_ClearSwitchGateControlListCompleteFlag(pEnetHandle->EnetBase); } } } } } } } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } /** * @brief Enable or disable the frame preemption function * @param[in] pEnetHandle ENET driver handle * @param[in] pConfig Preemption configuration structure * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Enable or disable frame preemption successfully * @retval other values Enable or disable frame preemption failed */ ENET_StatusType Enet_TSN_PreemptionConfig(ENET_HandleType *pEnetHandle, const ENET_PreemptionConfigType *pConfig) { uint8_t u8Channel; uint32_t u32Classification; ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_PREEMPTION_CONFIG_SERVICE_ID)) { if (pConfig == NULL_PTR) { ENET_ReportDevError(ENET_PREEMPTION_CONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (0u != Enet_AssertPreemptionConfiguration(pConfig)) { ENET_ReportDevError(ENET_PREEMPTION_CONFIG_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_PREEMPTION_CONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (pEnetHandle->TxChannelCount < 2u) { ENET_ReportDevError(ENET_PREEMPTION_CONFIG_SERVICE_ID, ENET_E_PARAM_TXCHANNEL); } else { #endif if (pConfig->PreemptionEnable) { u32Classification = 0u; for (u8Channel = 0u; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { if (pConfig->Classification[u8Channel] == ENET_CLISSIFICATION_PREEMPTABLE) { u32Classification |= 1u << u8Channel; } } ENET_HWA_MTL_SetPreemptionClassification(pEnetHandle->EnetBase, (uint8_t)u32Classification); ENET_HWA_MTL_SetPreemptionReleaseAdvance(pEnetHandle->EnetBase, pConfig->ReleaseAdvance); ENET_HWA_MTL_SetPreemptionHoldAdvance(pEnetHandle->EnetBase, pConfig->HoldAdvance); ENET_HWA_MAC_SetFramePreemptionEnFlag(pEnetHandle->EnetBase, ENET_TRUE); } else { ENET_HWA_MAC_SetFramePreemptionEnFlag(pEnetHandle->EnetBase, ENET_FALSE); } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } } #endif return eStatus; } #endif /* ENET_SUPPORT_TIME_SENSITIVE_NETWORK */ /** * @brief ENET get MAC management counters configuration * @param[in] pEnetHandle ENET driver handle * @param[in] pMMCConfig MAC management configuration type */ void Enet_GetMMCConfig(const ENET_HandleType *pEnetHandle, ENET_MMCConfigType *pMMCConfig) { uint32_t u32IntMask = 0u; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_MMCCONFIG_SERVICE_ID)) { if (pMMCConfig == NULL_PTR) { ENET_ReportDevError(ENET_GET_MMCCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_GET_MMCCONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif pMMCConfig->UpdateDropedBroadcast = ENET_HWA_MAC_GetUpdateMmcCntForDroppedBroadcastPktEnFlag(pEnetHandle->EnetBase); pMMCConfig->PresetLevel = ENET_HWA_MAC_GetMmcCounterPresetLevel(pEnetHandle->EnetBase); pMMCConfig->ResetOnRead = ENET_HWA_MAC_GetMmcCounterResetOnReadEnFlag(pEnetHandle->EnetBase); pMMCConfig->CounterRollover = !ENET_HWA_MAC_GetMmcCounterStopRolloverEnFlag(pEnetHandle->EnetBase); u32IntMask = ENET_HWA_MAC_GetMmcRxInterruptMask(pEnetHandle->EnetBase); pMMCConfig->MmcRxCntIntEn = (~u32IntMask) & 0x03FFFFFFu; u32IntMask = ENET_HWA_MAC_GetMmcTxInterruptMask(pEnetHandle->EnetBase); pMMCConfig->MmcTxCntIntEn = (~u32IntMask) & 0x03FFFFFFu; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif } /** * @brief ENET set MAC management counters configuration * @param[in] pEnetHandle ENET driver handle * @param[in] pMMCConfig MAC management configuration type */ void Enet_SetMMCConfig(ENET_HandleType *pEnetHandle, const ENET_MMCConfigType *pMMCConfig) { uint32_t u32IntMask = 0u; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_MMCCONFIG_SERVICE_ID)) { if (pMMCConfig == NULL_PTR) { ENET_ReportDevError(ENET_SET_MMCCONFIG_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_MMCCONFIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_SetUpdateMmcCntForDroppedBroadcastPktEnFlag(pEnetHandle->EnetBase, pMMCConfig->UpdateDropedBroadcast); ENET_HWA_MAC_SetMmcCounterPresetLevel(pEnetHandle->EnetBase, pMMCConfig->PresetLevel); ENET_HWA_MAC_SetMmcCounterResetOnReadEnFlag(pEnetHandle->EnetBase, pMMCConfig->ResetOnRead); ENET_HWA_MAC_SetMmcCounterStopRolloverEnFlag(pEnetHandle->EnetBase, pMMCConfig->CounterRollover ? false : true); u32IntMask = ENET_HWA_MAC_GetMmcRxInterruptMask(pEnetHandle->EnetBase); u32IntMask = (u32IntMask & 0xFC000000u) | (~(pMMCConfig->MmcRxCntIntEn & 0x03FFFFFFu)); ENET_HWA_MAC_SetMmcRxInterruptMask(pEnetHandle->EnetBase, u32IntMask); u32IntMask = ENET_HWA_MAC_GetMmcTxInterruptMask(pEnetHandle->EnetBase); u32IntMask = (u32IntMask & 0xFC000000u) | (~(pMMCConfig->MmcTxCntIntEn & 0x03FFFFFFu)); ENET_HWA_MAC_SetMmcTxInterruptMask(pEnetHandle->EnetBase, u32IntMask); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif } /** * @brief Preset MAC management counters * @param[in] pEnetHandle ENET driver handle */ void Enet_MMCCounterPreset(ENET_HandleType *pEnetHandle) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_COUNTER_PRESET_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_COUNTER_PRESET_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_PresetMmcCounters(pEnetHandle->EnetBase); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief Freeze MMC counters to their current value * @param[in] pEnetHandle ENET driver handle * @param[in] bFreeze Enable or disable Freeze */ void Enet_MMCCounterFreeze(ENET_HandleType *pEnetHandle, bool bFreeze) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_COUNTER_FREEZE_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_COUNTER_FREEZE_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_SetMmcCounterFreezeStatus(pEnetHandle->EnetBase, bFreeze); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief Reset MAC management counters to zero * @param[in] pEnetHandle ENET driver handle */ void Enet_MMCCounterReset(ENET_HandleType *pEnetHandle) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_COUNTER_RESET_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_COUNTER_RESET_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_ResetMmcCounters(pEnetHandle->EnetBase); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief Get MMC transmit counters interrupt status * @param[in] pEnetHandle ENET driver handle * @note User must read the respective counter to clear the MMC interrupt bit. */ uint32_t Enet_GetMMCTxInterrupts(const ENET_HandleType *pEnetHandle) { uint32_t u32Status = 0; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_GET_TXINT_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_GET_TXINT_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif u32Status = ENET_HWA_MAC_GetMmcTxInterruptStatus(pEnetHandle->EnetBase) & 0x03FFFFFFu; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif return u32Status; } /** * @brief Get MMC receive counters interrupt status * @param[in] pEnetHandle ENET driver handle * @note User must read the respective counter to clear the MMC interrupt bit. */ uint32_t Enet_GetMMCRxInterrupts(const ENET_HandleType *pEnetHandle) { uint32_t u32Status = 0; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_GET_RXINT_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_GET_RXINT_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif u32Status = ENET_HWA_MAC_GetMmcRxInterruptStatus(pEnetHandle->EnetBase) & 0x03FFFFFFu; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif return u32Status; } /** * @brief Get ENET MAC management transmit counters * @param[in] pEnetHandle ENET driver handle * @param[in] eCounter MAC management transmit counter type */ uint32_t Enet_GetMMCTxCounter(const ENET_HandleType *pEnetHandle, Enet_MMCTxCounterType eCounter) { volatile const uint32_t *pCounters; uint32_t u32Counter = 0; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_GET_TXCOUNTER_SERVICE_ID)) { if ((uint32_t)eCounter > (uint32_t)ENET_CTR_TX_OSIZE_PACKETS_GOOD) { ENET_ReportDevError(ENET_MMC_GET_TXCOUNTER_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_GET_TXCOUNTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif pCounters = ((volatile const uint32_t *)&(pEnetHandle->EnetBase->TX_OCTET_COUNT_GOOD_BAD)) + (uint32_t)eCounter; u32Counter = *pCounters; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return u32Counter; } /** * @brief Get ENET MAC management receive counters * @param[in] pEnetHandle ENET driver handle * @param[in] eCounter MAC management receive counter type */ uint32_t Enet_GetMMCRxCounter(const ENET_HandleType *pEnetHandle, Enet_MMCRxCounterType eCounter) { volatile const uint32_t *pCounters; uint32_t u32Counter = 0; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_MMC_GET_RXCOUNTER_SERVICE_ID)) { if ((uint32_t)eCounter > (uint32_t)ENET_CTR_RX_CONTROL_PACKETS_GOOD) { ENET_ReportDevError(ENET_MMC_GET_RXCOUNTER_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_MMC_GET_RXCOUNTER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif pCounters = ((volatile const uint32_t *)&(pEnetHandle->EnetBase->RX_PACKETS_COUNT_GOOD_BAD)) + (uint32_t)eCounter; u32Counter = *pCounters; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif return u32Counter; } /** * @brief Get flow control configuration * @param[in] pEnetHandle ENET driver handle * @param[in] pFlowControl MAC flow control configuration */ void Enet_GetFlowControlConfig(const ENET_HandleType *pEnetHandle, ENET_FlowControlType *pFlowControl) { uint32_t u8Channel; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_GET_FLOWCTRL_SERVICE_ID)) { if (pFlowControl == NULL_PTR) { ENET_ReportDevError(ENET_GET_FLOWCTRL_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_GET_FLOWCTRL_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { pFlowControl->RxQueueConfig[u8Channel].RxDeactiveThreshold = ENET_HWA_MTL_GetRxDeactivateFlowCtrlThres(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel); pFlowControl->RxQueueConfig[u8Channel].RxActiveThreshold = ENET_HWA_MTL_GetRxActivateFlowCtrlThres(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel); pFlowControl->RxQueueConfig[u8Channel].RxHwFlowCtrlEnable = ENET_HWA_MTL_GetRxHwFlowCtrlEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel); } pFlowControl->PauseTime = ENET_HWA_MAC_GetQnTxPauseTime(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0); pFlowControl->ZeroQuantaPauseDisable = ENET_HWA_MAC_GetQnTxZeroQuantaPauseDisableFlag(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0); pFlowControl->PauseThreshold = ENET_HWA_MAC_GetQnTxPauseLowThreshold(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0); pFlowControl->MacTxFlowCtrlEnable = ENET_HWA_MAC_GetQnTxFlowCtrlEnableFlag(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0); pFlowControl->UnicastPauseEnable = ENET_HWA_MAC_GetUnicastPausePacketDetectEnFlag(pEnetHandle->EnetBase); pFlowControl->MacRxFlowCtrlEnable = ENET_HWA_MAC_GetRxFlowCtrlEnFlag(pEnetHandle->EnetBase); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } #endif } /** * @brief Configure and enable flow control * @param[in] pEnetHandle ENET driver handle * @param[in] pFlowControl MAC flow control configuration */ void Enet_FlowControlConfig(ENET_HandleType *pEnetHandle, const ENET_FlowControlType *pFlowControl) { uint32_t u8Channel; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SET_FLOWCTRL_SERVICE_ID)) { if (pFlowControl == NULL_PTR) { ENET_ReportDevError(ENET_SET_FLOWCTRL_SERVICE_ID, ENET_E_PARAM_POINTER); } else { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SET_FLOWCTRL_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { if (0u != Enet_AssertFlowControlConfiguration(pEnetHandle, pFlowControl)) { ENET_ReportDevError(ENET_SET_FLOWCTRL_SERVICE_ID, ENET_E_PARAM_ASSERTION); } else { #endif for (u8Channel = 0u; u8Channel < pEnetHandle->RxChannelCount; ++u8Channel) { ENET_HWA_MTL_SetRxDeactivateFlowCtrlThres(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pFlowControl->RxQueueConfig[u8Channel].RxDeactiveThreshold); ENET_HWA_MTL_SetRxActivateFlowCtrlThres(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pFlowControl->RxQueueConfig[u8Channel].RxActiveThreshold); ENET_HWA_MTL_SetRxHwFlowCtrlEnFlag(pEnetHandle->EnetBase, (ENET_MTL_QueueType)u8Channel, pFlowControl->RxQueueConfig[u8Channel].RxHwFlowCtrlEnable); } ENET_HWA_MAC_SetQnTxPauseTime(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0, pFlowControl->PauseTime); ENET_HWA_MAC_SetQnTxZeroQuantaPauseDisableFlag(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0, pFlowControl->ZeroQuantaPauseDisable); ENET_HWA_MAC_SetQnTxPauseLowThreshold(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0, pFlowControl->PauseThreshold); ENET_HWA_MAC_SetQnTxFlowCtrlEnableFlag(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0, pFlowControl->MacTxFlowCtrlEnable); ENET_HWA_MAC_SetUnicastPausePacketDetectEnFlag(pEnetHandle->EnetBase, pFlowControl->UnicastPauseEnable); ENET_HWA_MAC_SetRxFlowCtrlEnFlag(pEnetHandle->EnetBase, pFlowControl->MacRxFlowCtrlEnable); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } } } #endif } /** * @brief Generate and transmits a single pause packet * @param[in] pEnetHandle ENET driver handle */ void Enet_FlowControlSoftwareTrigger(ENET_HandleType *pEnetHandle) { #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_FLOWCTRL_SOFTTRIG_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_FLOWCTRL_SOFTTRIG_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif ENET_HWA_MAC_InitiatePausePacketOrBackpressure(pEnetHandle->EnetBase, ENET_MTL_QUEUE_0); #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } #if ENET_SUPPORT_TIME_SENSITIVE_NETWORK /** * @brief Enable EST Offset Mode * @param[in] pEnetHandle ENET driver handle * @param[in] bEnable Enable or disable EST Offset Mode * @return ENET_StatusType * @retval ENET_STATUS_SUCCESS Operation successful * @retval other values Operation failed */ ENET_StatusType Enet_TSN_EstOffsetModeEnable(ENET_HandleType *pEnetHandle, bool bEnable) { ENET_StatusType eStatus = ENET_STATUS_INVALID_PARAM; #if (ENET_DEV_ERROR_REPORT == STD_ON) /* Check handle validity */ if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_EST_OFFSET_MODE_SERVICE_ID)) { /* Check driver state */ if (pEnetHandle->State == ENET_STATE_UNINIT) { eStatus = ENET_STATUS_NOT_READY; ENET_ReportDevError(ENET_EST_OFFSET_MODE_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif /* Call the hardware abstraction function */ ENET_HWA_MTL_SetEstOffsetModeEnFlag(pEnetHandle->EnetBase, bEnable); eStatus = ENET_STATUS_SUCCESS; #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif return eStatus; } #endif /** * @brief ENET driver PTP interrupt handler * @param[in] pEnetHandle ENET driver handle */ static void Enet_PTPIrqHandler(ENET_HandleType *pEnetHandle) { uint32_t u32PTPStatus; u32PTPStatus = pEnetHandle->EnetBase->MAC_TIMESTAMP_STATUS; if (pEnetHandle->EventCallback != NULL_PTR) { if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTARGT0_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME0_REACHED); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTRGTERR0_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME0_ERROR); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTARGT1_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME1_REACHED); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTRGTERR1_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME1_ERROR); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTARGT2_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME2_REACHED); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTRGTERR2_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME2_ERROR); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTARGT3_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME3_REACHED); } if (0u != (u32PTPStatus & ENET_MAC_TIMESTAMP_STATUS_TSTRGTERR3_MASK)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_TARGET_TIME3_ERROR); } } } /** * @brief ENET driver MMC interrupt handler * @param[in] pEnetHandle ENET driver handle */ static void Enet_MMCIrqHandler(ENET_HandleType *pEnetHandle) { uint32_t u32RxStatus, u32TxStatus, i; u32RxStatus = pEnetHandle->EnetBase->MMC_RX_INTERRUPT; u32TxStatus = pEnetHandle->EnetBase->MMC_TX_INTERRUPT; if (pEnetHandle->EventCallback != NULL_PTR) { if (0u != (u32RxStatus & 0x03FFFFFFu)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_MMC_RX_COUNTER); } if (0u != (u32TxStatus & 0x03FFFFFFu)) { pEnetHandle->EventCallback(pEnetHandle, ENET_EVENT_MMC_TX_COUNTER); } } else { for (i = (uint32_t)ENET_CTR_RX_PACKETS_COUNT_GOOD_BAD; i <= (uint32_t)ENET_CTR_RX_CONTROL_PACKETS_GOOD; ++i) { if (0u != (u32RxStatus & (1u << i))) { (void)(*(volatile const uint32_t *)(&(pEnetHandle->EnetBase->RX_PACKETS_COUNT_GOOD_BAD) + i)); } } for (i = (uint32_t)ENET_CTR_TX_OCTET_COUNT_GOOD_BAD; i <= (uint32_t)ENET_CTR_TX_OSIZE_PACKETS_GOOD; ++i) { if (0u != (u32TxStatus & (1u << i))) { (void)(*(volatile const uint32_t *)(&(pEnetHandle->EnetBase->TX_OCTET_COUNT_GOOD_BAD) + i)); } } } } /** * @brief ENET driver MAC interrupt handler * @param[in] pEnetHandle ENET driver handle */ static void Enet_MACIrqHandler(ENET_HandleType *pEnetHandle) { uint32_t u32Status, u32IntEnable; u32Status = ENET_HWA_MAC_GetInterruptStatus(pEnetHandle->EnetBase); u32IntEnable = ENET_HWA_MAC_GetInterruptEnable(pEnetHandle->EnetBase); if (0u != (u32Status & ENET_MAC_INTERRUPT_STATUS_MDIOIS_MASK) && 0u != (u32IntEnable & ENET_MAC_INTERRUPT_ENABLE_MDIOIE_MASK)) { } if (0u != (u32Status & ENET_MAC_INTERRUPT_STATUS_RXSTSIS_MASK) && 0u != (u32IntEnable & ENET_MAC_INTERRUPT_ENABLE_RXSTSIE_MASK)) { } if (0u != (u32Status & ENET_MAC_INTERRUPT_STATUS_TXSTSIS_MASK) && 0u != (u32IntEnable & ENET_MAC_INTERRUPT_ENABLE_TXSTSIE_MASK)) { } if (0u != (u32Status & ENET_MAC_INTERRUPT_STATUS_TSIS_MASK) && 0u != (u32IntEnable & ENET_MAC_INTERRUPT_ENABLE_TSIE_MASK)) { Enet_PTPIrqHandler(pEnetHandle); } if (0u != (u32Status & ENET_MAC_INTERRUPT_STATUS_MMCIS_MASK)) { Enet_MMCIrqHandler(pEnetHandle); } if (0u != (u32Status & ENET_MAC_INTERRUPT_STATUS_PHYIS_MASK) && 0u != (u32IntEnable & ENET_MAC_INTERRUPT_ENABLE_PHYIE_MASK)) { } } /** * @brief ENET driver MTL interrupt handler * @param[in] pEnetHandle ENET driver handle */ static void Enet_MTLIrqHandler(ENET_HandleType *pEnetHandle) { ENET_Type *EnetBase = pEnetHandle->EnetBase; uint32_t u32Status; uint8_t u8Channel; for (u8Channel = 0u; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { if (0u != (EnetBase->MTL.INTERRUPT_STATUS & (1u << u8Channel))) { u32Status = ENET_HWA_MTL_GetInterruptCtrlStatus(EnetBase, (ENET_MTL_QueueType)u8Channel); if (0u != (u32Status & ENET_MTL_Qn_INTERRUPT_CONTROL_STATUS_RXOVFIS_MASK) && 0u != (u32Status & ENET_MTL_Qn_INTERRUPT_CONTROL_STATUS_RXOIE_MASK)) { } if (0u != (u32Status & ENET_MTL_Qn_INTERRUPT_CONTROL_STATUS_ABPSIS_MASK) && 0u != (u32Status & ENET_MTL_Qn_INTERRUPT_CONTROL_STATUS_ABPSIE_MASK)) { } if (0u != (u32Status & ENET_MTL_Qn_INTERRUPT_CONTROL_STATUS_TXUNFIS_MASK) && 0u != (u32Status & ENET_MTL_Qn_INTERRUPT_CONTROL_STATUS_TXUIE_MASK)) { } ENET_HWA_MTL_ClearAllIntStatus(EnetBase, (ENET_MTL_QueueType)u8Channel); } } } /** * @brief ENET driver DMA interrupt handler * @param[in] pEnetHandle ENET driver handle * @param[in] u8Channel ENET DMA channel */ static void Enet_DMAIrqHandler(ENET_HandleType *pEnetHandle, uint8_t u8Channel) { uint32_t u32IntEn; uint32_t u32IntStatus; u32IntEn = ENET_HWA_DMA_GetEnabledInterrupts(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); u32IntStatus = ENET_HWA_DMA_GetCurrentStatus(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); /* Handle DMA Abnormal Interrupts */ if (0u != (u32IntStatus & ENET_DMA_CHn_STATUS_AIS_MASK) && 0u != (u32IntEn & ENET_DMA_CHn_INTERRUPT_ENABLE_AIE_MASK)) { if (0u != (u32IntStatus & ENET_DMA_CHn_STATUS_FBE_MASK)) { ENET_HWA_DMA_DisableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_ABNORMAL_INTERRUPT); ENET_HWA_DMA_DisableInterrupt(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel, ENET_DMA_NORMAL_INTERRUPT); pEnetHandle->State = ENET_STATE_ERROR; } else { } /* Clear Abnormal Interrupt status */ ENET_HWA_DMA_ClearAllAbnormalInterruptFlags(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); } /* Handle DMA Normal Interrupts */ if (0u != (u32IntStatus & ENET_DMA_CHn_STATUS_NIS_MASK) && (0u != (u32IntEn & ENET_DMA_CHn_INTERRUPT_ENABLE_NIE_MASK))) { /* Clear Normal Interrupt status */ ENET_HWA_DMA_ClearAllNormalInterruptFlags(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel); } } /** * @brief ENET driver system interrupt handler * @param[in] pEnetHandle ENET driver handle */ void Enet_SystemIrqHandler(ENET_HandleType *pEnetHandle) { uint8_t u8Channel; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_SYSIRQ_HANDLER_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_SYSIRQ_HANDLER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif if (ENET_HWA_DMA_GetMACIntStatus(pEnetHandle->EnetBase)) { Enet_MACIrqHandler(pEnetHandle); } if (ENET_HWA_DMA_GetMTLIntStatus(pEnetHandle->EnetBase)) { Enet_MTLIrqHandler(pEnetHandle); } for (u8Channel = 0; u8Channel < ENET_CHANNEL_COUNT; ++u8Channel) { if (ENET_HWA_DMA_GetDMAChannelIntStatus(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)u8Channel)) { Enet_DMAIrqHandler(pEnetHandle, u8Channel); } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief ENET driver DMA RX channel interrupt handler * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel ENET DMA channel */ ENET_DECLARE_EFFICIENT_CODE( void Enet_RxIrqHandler(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel)) { uint32_t u32IntEn; uint32_t u32IntStatus; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_RXIRQ_HANDLER_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_RXIRQ_HANDLER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif u32IntEn = ENET_HWA_DMA_GetEnabledInterrupts(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); u32IntStatus = ENET_HWA_DMA_GetCurrentStatus(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); if ((0u != (u32IntStatus & ENET_DMA_CHn_STATUS_RI_MASK)) && (0u != (u32IntEn & ENET_DMA_CHn_INTERRUPT_ENABLE_RIE_MASK))) { /* Clear RI flag bit */ ENET_HWA_DMA_ClearRxInterruptFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); if (pEnetHandle->RxReady != NULL_PTR) { pEnetHandle->RxReady(pEnetHandle, eChannel); } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } /** * @brief ENET driver DMA TX channel interrupt handler * @param[in] pEnetHandle ENET driver handle * @param[in] eChannel ENET DMA channel */ ENET_DECLARE_EFFICIENT_CODE( void Enet_TxIrqHandler(ENET_HandleType *pEnetHandle, ENET_ChannelType eChannel)) { uint32_t u32IntEn; uint32_t u32IntStatus; #if (ENET_DEV_ERROR_REPORT == STD_ON) if (0u == Enet_HandleInstanceCheck(pEnetHandle, ENET_TXIRQ_HANDLER_SERVICE_ID)) { if (pEnetHandle->State == ENET_STATE_UNINIT) { ENET_ReportDevError(ENET_TXIRQ_HANDLER_SERVICE_ID, ENET_E_DRIVER_UNINIT); } else { #endif u32IntEn = ENET_HWA_DMA_GetEnabledInterrupts(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); u32IntStatus = ENET_HWA_DMA_GetCurrentStatus(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); if ((0u != (u32IntStatus & ENET_DMA_CHn_STATUS_TI_MASK)) && (0u != (u32IntEn & ENET_DMA_CHn_INTERRUPT_ENABLE_TIE_MASK))) { /* Clear TI flag bit */ ENET_HWA_DMA_ClearTxInterruptFlag(pEnetHandle->EnetBase, (ENET_DMA_ChannelType)eChannel); if (pEnetHandle->TxComplete != NULL_PTR) { pEnetHandle->TxComplete(pEnetHandle, eChannel); } } #if (ENET_DEV_ERROR_REPORT == STD_ON) } } #endif } #endif /* ENET_INSTANCE_COUNT > 0u */