diff --git a/APP_Framework/Applications/main.c b/APP_Framework/Applications/main.c index 5283b461c..59009df03 100644 --- a/APP_Framework/Applications/main.c +++ b/APP_Framework/Applications/main.c @@ -15,6 +15,8 @@ // #include #include +extern void ShowTask(); + extern int FrameworkInit(); extern void ApplicationOtaTaskInit(void); int main(void) @@ -24,6 +26,10 @@ int main(void) #ifdef APPLICATION_OTA ApplicationOtaTaskInit(); #endif + while(1){ + // ShowTask(); + PrivTaskDelay(2000); + } return 0; } // int cppmain(void); diff --git a/APP_Framework/Framework/connection/industrial_ethernet/openPOWERLINK/stack/src/kernel/edrv/edrv-xiuos.c b/APP_Framework/Framework/connection/industrial_ethernet/openPOWERLINK/stack/src/kernel/edrv/edrv-xiuos.c index 2f12b5a4b..0f11af7dc 100644 --- a/APP_Framework/Framework/connection/industrial_ethernet/openPOWERLINK/stack/src/kernel/edrv/edrv-xiuos.c +++ b/APP_Framework/Framework/connection/industrial_ethernet/openPOWERLINK/stack/src/kernel/edrv/edrv-xiuos.c @@ -139,6 +139,8 @@ This function initializes the Ethernet driver. //------------------------------------------------------------------------------ tOplkError edrv_init(const tEdrvInitParam* pEdrvInitParam_p) { + uint8_t enet_port = 0; ///< use enet port 0 + // Check parameter validity ASSERT(pEdrvInitParam_p != NULL); @@ -153,7 +155,7 @@ tOplkError edrv_init(const tEdrvInitParam* pEdrvInitParam_p) edrvInstance_l.fStartCommunication = TRUE; - lwip_config_net(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, lwip_gwaddr); gnetif.input = ethernetInput; edrvInstance_l.pNetif = &gnetif; diff --git a/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c b/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c index 74eba30c9..5c0dc8867 100755 --- a/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c +++ b/APP_Framework/Framework/control/plc/interoperability/socket/plc_socket.c @@ -347,6 +347,7 @@ void PlcSocketTask(int argc, char *argv[]) { int result = 0; pthread_t th_id; + uint8_t enet_port = 0; ///< test enet port 0 pthread_attr_t attr; attr.schedparam.sched_priority = LWIP_DEMO_TASK_PRIO; @@ -355,7 +356,7 @@ void PlcSocketTask(int argc, char *argv[]) PlcCheckParam(argc, argv); - lwip_config_net(lwip_ipaddr, lwip_netmask, param->ip); + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, param->ip); PrivTaskCreate(&th_id, &attr, PlcSocketStart, param); } diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/board.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/board.c index dd080a68a..6adb5f8e8 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/board.c +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/board.c @@ -35,6 +35,10 @@ Modification: #include #endif +#ifdef BSP_USING_LWIP +extern int ETH_BSP_Config(); +#endif + #if __CORTEX_M == 7 void BOARD_ConfigMPU(void) { @@ -368,6 +372,79 @@ void BOARD_ConfigMPU(void) } #endif +void BOARD_InitModuleClock(void) +{ + const clock_sys_pll1_config_t sysPll1Config = { + .pllDiv2En = true, + }; + CLOCK_InitSysPll1(&sysPll1Config); + + clock_root_config_t rootCfg = {.mux = 4, .div = 10}; + +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT + /* Generate 50M root clock. */ + CLOCK_SetRootClock(kCLOCK_Root_Enet1, &rootCfg); +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT + /* Generate 125M root clock. */ + rootCfg.mux = 4; + rootCfg.div = 4; + CLOCK_SetRootClock(kCLOCK_Root_Enet2, &rootCfg); +#endif + + /* Select syspll2pfd3, 528*18/24 = 396M */ + CLOCK_InitPfd(kCLOCK_PllSys2, kCLOCK_Pfd3, 24); + rootCfg.mux = 7; + rootCfg.div = 2; + CLOCK_SetRootClock(kCLOCK_Root_Bus, &rootCfg); /* Generate 198M bus clock. */ +} + +void IOMUXC_SelectENETClock(void) +{ +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT + IOMUXC_GPR->GPR4 |= 0x3; /* 50M ENET_REF_CLOCK output to PHY and ENET module. */ +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT + IOMUXC_GPR->GPR5 |= IOMUXC_GPR_GPR5_ENET1G_RGMII_EN_MASK; /* bit1:iomuxc_gpr_enet_clk_dir + bit0:GPR_ENET_TX_CLK_SEL(internal or OSC) */ +#endif +} +/*! + * @brief Utility function for comparing arrays + */ +static uint8_t compareArrays(uint8_t a[], uint8_t b[], int len) +{ + for (int i=0; imiiMode = kENET_RmiiMode; + config->miiSpeed = kENET_MiiSpeed100M; + } + else + { + config->miiMode = kENET_RgmiiMode; + config->miiSpeed = kENET_MiiSpeed1000M; + } +} + /* This is the timer interrupt service routine. */ void SysTick_Handler(int irqn, void *arg) { @@ -381,6 +458,10 @@ struct InitSequenceDesc _board_init[] = // { "hw_pin", Imxrt1052HwGpioInit }, #endif +#ifdef BSP_USING_LWIP + {"ETH_BSP", ETH_BSP_Config}, +#endif + { " NONE ",NONE }, }; @@ -395,6 +476,15 @@ void InitBoardHardware() BOARD_ConfigMPU(); BOARD_InitPins(); BOARD_BootClockRUN(); + BOARD_InitModuleClock(); + IOMUXC_SelectENETClock(); + +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT + BOARD_InitEnetPins(); +#endif +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT + BOARD_InitEnet1GPins(); +#endif // NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/config.mk b/Ubiquitous/XiZi/board/imxrt1176-sbc/config.mk index 79ea5ae8e..f8a1c2210 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/config.mk +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/config.mk @@ -3,11 +3,22 @@ export CROSS_COMPILE ?=/usr/bin/arm-none-eabi- export CFLAGS := -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -Dgcc -O0 -gdwarf-2 -g -fgnu89-inline -Wa,-mimplicit-it=thumb export AFLAGS := -c -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -x assembler-with-cpp -Wa,-mimplicit-it=thumb -gdwarf-2 export LFLAGS := -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -Wl,--gc-sections,-Map=XiZi-imxrt1176-sbc.map,-cref,-u,Reset_Handler -T $(BSP_ROOT)/link.lds + +ifeq ($(CONFIG_LIB_MUSLLIB), y) +export LFLAGS += -nostdlib -nostdinc # -fno-builtin -nodefaultlibs +export LIBCC := -lgcc +export LINK_MUSLLIB := $(KERNEL_ROOT)/lib/musllib/libmusl.a +endif + +ifeq ($(CONFIG_RESOURCES_LWIP), y) +export LINK_LWIP := $(KERNEL_ROOT)/resources/ethernet/LwIP/liblwip.a +endif + export CXXFLAGS := -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -Dgcc -O0 -gdwarf-2 -g # export APPLFLAGS := -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -Wl,--gc-sections,-Map=XiZi-app.map,-cref,-u, -T $(BSP_ROOT)/link_userspace.lds -export DEFINES := -DHAVE_CCONFIG_H -DCPU_MIMXRT1052CVL5B -DSKIP_SYSCLK_INIT -DEVK_MCIMXRM -DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 -DXIP_EXTERNAL_FLASH=1 -D__STARTUP_INITIALIZE_NONCACHEDATA -D__STARTUP_CLEAR_BSS +export DEFINES := -DHAVE_CCONFIG_H -DCPU_MIMXRT1176DVMAA_cm7 -DSKIP_SYSCLK_INIT -DEVK_MCIMXRM -DFSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1 -DXIP_EXTERNAL_FLASH=1 -D__STARTUP_INITIALIZE_NONCACHEDATA -D__STARTUP_CLEAR_BSS export ARCH = arm export MCU = cortex-m7 diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/include/board.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/include/board.h index 775d89275..2fc630448 100755 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/include/board.h +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/include/board.h @@ -24,21 +24,31 @@ Modification: #include "fsl_common.h" #include "fsl_gpio.h" #include "fsl_clock.h" -// #include "fsl_enet.h" +#include "fsl_enet.h" #include "clock_config.h" +#include "pin_mux.h" #include #include +#define BOARD_NET_COUNT (2) +/* MAC address configuration. */ +#define configMAC_ADDR {0x02, 0x12, 0x13, 0x10, 0x15, 0x11} +#define configMAC_ADDR_ETH1 {0x02, 0x12, 0x13, 0x10, 0x15, 0x12} + +/*! @brief The ENET0 PHY address. */ +#define BOARD_ENET0_PHY_ADDRESS (0x02U) /* Phy address of enet port 0. */ + +/*! @brief The ENET1 PHY address. */ +#define BOARD_ENET1_PHY_ADDRESS (0x07U) /* Phy address of enet port 1. */ + +#define BOARD_FLASH_SIZE (0x1000000U) + extern int heap_start; extern int heap_end; #define HEAP_BEGIN (&heap_start) #define HEAP_END (&heap_end) - -#define BOARD_FLASH_SIZE (0x1000000U) - #define HEAP_SIZE ((uint32_t)HEAP_END - (uint32_t)HEAP_BEGIN) - void InitBoardHardware(void); /******************************************************************************* @@ -57,9 +67,6 @@ void InitBoardHardware(void); 1 bits for subpriority */ #define NVIC_PRIORITYGROUP_4 0x00000003U /*!< 4 bits for pre-emption priority*/ -/*! @brief The ENET PHY address. */ -#define BOARD_ENET0_PHY_ADDRESS (0x0U) /* Phy address of enet port 0. */ - #if defined(__cplusplus) diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/include/pin_mux.h similarity index 84% rename from Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.h rename to Ubiquitous/XiZi/board/imxrt1176-sbc/include/pin_mux.h index 0fa3f18bd..b61bdb346 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.h +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/include/pin_mux.h @@ -69,6 +69,17 @@ void BOARD_InitBootPins(void); * */ void BOARD_InitPins(void); +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitEnetPins(void); /* Function assigned for the Cortex-M7F */ + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitEnet1GPins(void); /* Function assigned for the Cortex-M7F */ #if defined(__cplusplus) } diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/link.lds b/Ubiquitous/XiZi/board/imxrt1176-sbc/link.lds index 71594f535..5b0d78cbb 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/link.lds +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/link.lds @@ -48,16 +48,15 @@ Modification: /* Entry Point */ ENTRY(Reset_Handler) -HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; -STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x1000; +STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x2000; -/* Specify the memory areas */ +/* Specify the memory areas- */ MEMORY { /* define flash 32MB */ m_boot_data (RX) : ORIGIN = 0x30000000, LENGTH = 0x00001000 m_image_vertor_table (RX) : ORIGIN = 0x30001000, LENGTH = 0x00001000 - m_interrupts (RX) : ORIGIN = 0x30002000, LENGTH = 0x00000400 + m_interrupts (RX) : ORIGIN = 0x30002000, LENGTH = 0x00001000 m_text (RX) : ORIGIN = 0x30002400, LENGTH = 0x01FFDC00 /* define itcm 256KB */ @@ -91,12 +90,14 @@ SECTIONS { KEEP(*(.boot_hdr.conf)) } > m_boot_data - + .image_vertor_table : { + . = ALIGN(4); KEEP(*(.boot_hdr.ivt)) KEEP(*(.boot_hdr.boot_data)) KEEP(*(.boot_hdr.dcd_data)) + . = ALIGN(4); } > m_image_vertor_table /* The startup code goes first into internal RAM */ @@ -240,15 +241,15 @@ SECTIONS *(NonCacheable.init) . = ALIGN(4); __noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ - } > sram_dtcm_cm7 + } > NCACHE_REGION . = __noncachedata_init_end__; .ncache : { *(NonCacheable) - . = ALIGN(4); + . = ALIGN(8192); __noncachedata_end__ = .; /* define a global symbol at ncache data end */ __NCACHE_REGION_END = .; - } > sram_dtcm_cm7 + } > NCACHE_REGION __DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__); text_end = ORIGIN(m_text) + LENGTH(m_text); diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Kconfig index 64caf9169..77a123e20 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Kconfig @@ -14,3 +14,12 @@ menuconfig BSP_USING_GPIO if BSP_USING_GPIO source "$BSP_DIR/third_party_driver/gpio/Kconfig" endif + +menuconfig BSP_USING_LWIP + bool "Using LwIP device" + default n + select RESOURCES_LWIP + + if BSP_USING_LWIP + source "$BSP_DIR/third_party_driver/ethernet/Kconfig" + endif diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Makefile index 7d2571e22..c3db9b6b5 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Makefile +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/Makefile @@ -1,7 +1,11 @@ -SRC_DIR := common +SRC_DIR := common gpio cm7 ifeq ($(CONFIG_BSP_USING_LPUART),y) SRC_DIR += uart endif +ifeq ($(CONFIG_BSP_USING_LWIP),y) + SRC_DIR += ethernet +endif + include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/cm7/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/cm7/Makefile new file mode 100644 index 000000000..c282a6fdf --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/cm7/Makefile @@ -0,0 +1,3 @@ +SRC_FILES :=fsl_cache.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.c index 247df3c75..914cbc217 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.c +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/common/pin_mux.c @@ -80,21 +80,172 @@ void BOARD_InitPins(void) { 0U); /* Software Input On Field: Input Path is determined by functionality */ IOMUXC_SetPinMux( IOMUXC_GPIO_AD_25_LPUART1_RXD, /* GPIO_AD_25 is configured as LPUART1_RXD */ - 0U); /* Software Input On Field: Input Path is determined by functionality */ + 1U); /* Software Input On Field: Input Path is determined by functionality */ IOMUXC_SetPinConfig( IOMUXC_GPIO_AD_24_LPUART1_TXD, /* GPIO_AD_24 PAD functional properties : */ - 0x02U); /* Slew Rate Field: Slow Slew Rate + 0x00U); /* Slew Rate Field: Slow Slew Rate Drive Strength Field: high driver Pull / Keep Select Field: Pull Disable, Highz Pull Up / Down Config. Field: Weak pull down Open Drain Field: Disabled */ IOMUXC_SetPinConfig( IOMUXC_GPIO_AD_25_LPUART1_RXD, /* GPIO_AD_25 PAD functional properties : */ - 0x02U); /* Slew Rate Field: Slow Slew Rate + 0x00U); /* Slew Rate Field: Slow Slew Rate Drive Strength Field: high driver Pull / Keep Select Field: Pull Disable, Highz Pull Up / Down Config. Field: Weak pull down Open Drain Field: Disabled */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_B2_11_GPIO8_IO21, /* GPIO_EMC_B2_11 is configured as GPIO8_IO21 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ +} + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitEnetPins: +- options: {callFromInitBoot: 'false', coreID: cm7, enableClock: 'true'} +- pin_list: + - {pin_num: P17, peripheral: GPIO9, signal: 'gpio_io, 11', pin_signal: GPIO_AD_12} + - {pin_num: U2, peripheral: ENET, signal: enet_mdc, pin_signal: GPIO_EMC_B2_19} + - {pin_num: R3, peripheral: ENET, signal: enet_mdio, pin_signal: GPIO_EMC_B2_20} + - {pin_num: E9, peripheral: ENET, signal: 'enet_tdata, 00', pin_signal: GPIO_DISP_B2_02} + - {pin_num: D7, peripheral: ENET, signal: 'enet_tdata, 01', pin_signal: GPIO_DISP_B2_03} + - {pin_num: C7, peripheral: ENET, signal: enet_tx_en, pin_signal: GPIO_DISP_B2_04} + - {pin_num: C9, peripheral: ENET, signal: enet_ref_clk, pin_signal: GPIO_DISP_B2_05, software_input_on: Enable, slew_rate: Fast} + - {pin_num: C6, peripheral: ENET, signal: 'enet_rdata, 00', pin_signal: GPIO_DISP_B2_06} + - {pin_num: D6, peripheral: ENET, signal: 'enet_rdata, 01', pin_signal: GPIO_DISP_B2_07} + - {pin_num: B5, peripheral: ENET, signal: enet_rx_en, pin_signal: GPIO_DISP_B2_08} + - {pin_num: D8, peripheral: ENET, signal: enet_rx_er, pin_signal: GPIO_DISP_B2_09} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitEnetPins, assigned for the Cortex-M7F core. + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitEnetPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* LPCG on: LPCG is ON. */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_12_GPIO9_IO11, /* GPIO_AD_12 is configured as GPIO9_IO11 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_02_ENET_TX_DATA00, /* GPIO_DISP_B2_02 is configured as ENET_TX_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_03_ENET_TX_DATA01, /* GPIO_DISP_B2_03 is configured as ENET_TX_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_04_ENET_TX_EN, /* GPIO_DISP_B2_04 is configured as ENET_TX_EN */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_05_ENET_REF_CLK, /* GPIO_DISP_B2_05 is configured as ENET_REF_CLK */ + 1U); /* Software Input On Field: Force input path of pad GPIO_DISP_B2_05 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_06_ENET_RX_DATA00, /* GPIO_DISP_B2_06 is configured as ENET_RX_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_07_ENET_RX_DATA01, /* GPIO_DISP_B2_07 is configured as ENET_RX_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_08_ENET_RX_EN, /* GPIO_DISP_B2_08 is configured as ENET_RX_EN */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B2_09_ENET_RX_ER, /* GPIO_DISP_B2_09 is configured as ENET_RX_ER */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_B2_19_ENET_MDC, /* GPIO_EMC_B2_19 is configured as ENET_MDC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_B2_20_ENET_MDIO, /* GPIO_EMC_B2_20 is configured as ENET_MDIO */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_DISP_B2_05_ENET_REF_CLK, /* GPIO_DISP_B2_05 PAD functional properties : */ + 0x03U); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: high drive strength + Pull / Keep Select Field: Pull Disable, Highz + Pull Up / Down Config. Field: Weak pull down + Open Drain Field: Disabled + Domain write protection: Both cores are allowed + Domain write protection lock: Neither of DWP bits is locked */ +} + + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitEnet1GPins: +- options: {callFromInitBoot: 'false', coreID: cm7, enableClock: 'true'} +- pin_list: + - {pin_num: E13, peripheral: ENET_1G, signal: enet_rx_en, pin_signal: GPIO_DISP_B1_00} + - {pin_num: D13, peripheral: ENET_1G, signal: enet_rx_clk, pin_signal: GPIO_DISP_B1_01} + - {pin_num: D11, peripheral: ENET_1G, signal: 'enet_rdata, 00', pin_signal: GPIO_DISP_B1_02} + - {pin_num: E11, peripheral: ENET_1G, signal: 'enet_rdata, 01', pin_signal: GPIO_DISP_B1_03} + - {pin_num: E10, peripheral: ENET_1G, signal: 'enet_rdata, 02', pin_signal: GPIO_DISP_B1_04} + - {pin_num: C11, peripheral: ENET_1G, signal: 'enet_rdata, 03', pin_signal: GPIO_DISP_B1_05} + - {pin_num: D10, peripheral: ENET_1G, signal: 'enet_tdata, 03', pin_signal: GPIO_DISP_B1_06} + - {pin_num: E12, peripheral: ENET_1G, signal: 'enet_tdata, 02', pin_signal: GPIO_DISP_B1_07} + - {pin_num: A15, peripheral: ENET_1G, signal: 'enet_tdata, 01', pin_signal: GPIO_DISP_B1_08} + - {pin_num: C13, peripheral: ENET_1G, signal: 'enet_tdata, 00', pin_signal: GPIO_DISP_B1_09} + - {pin_num: B14, peripheral: ENET_1G, signal: enet_tx_en, pin_signal: GPIO_DISP_B1_10} + - {pin_num: A14, peripheral: ENET_1G, signal: enet_tx_clk_io, pin_signal: GPIO_DISP_B1_11} + - {pin_num: N17, peripheral: ENET_1G, signal: enet_mdc, pin_signal: GPIO_AD_16} + - {pin_num: N15, peripheral: ENET_1G, signal: enet_mdio, pin_signal: GPIO_AD_17} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitEnet1GPins, assigned for the Cortex-M7F core. + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitEnet1GPins(void) { + CLOCK_EnableClock(kCLOCK_Iomuxc); /* LPCG on: LPCG is ON. */ + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_16_ENET_1G_MDC, /* GPIO_AD_16 is configured as ENET_1G_MDC */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_17_ENET_1G_MDIO, /* GPIO_AD_17 is configured as ENET_1G_MDIO */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_00_ENET_1G_RX_EN, /* GPIO_DISP_B1_00 is configured as ENET_1G_RX_EN */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_01_ENET_1G_RX_CLK, /* GPIO_DISP_B1_01 is configured as ENET_1G_RX_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_02_ENET_1G_RX_DATA00, /* GPIO_DISP_B1_02 is configured as ENET_1G_RX_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_03_ENET_1G_RX_DATA01, /* GPIO_DISP_B1_03 is configured as ENET_1G_RX_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_04_ENET_1G_RX_DATA02, /* GPIO_DISP_B1_04 is configured as ENET_1G_RX_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_05_ENET_1G_RX_DATA03, /* GPIO_DISP_B1_05 is configured as ENET_1G_RX_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_06_ENET_1G_TX_DATA03, /* GPIO_DISP_B1_06 is configured as ENET_1G_TX_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_07_ENET_1G_TX_DATA02, /* GPIO_DISP_B1_07 is configured as ENET_1G_TX_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_08_ENET_1G_TX_DATA01, /* GPIO_DISP_B1_08 is configured as ENET_1G_TX_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_09_ENET_1G_TX_DATA00, /* GPIO_DISP_B1_09 is configured as ENET_1G_TX_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_10_ENET_1G_TX_EN, /* GPIO_DISP_B1_10 is configured as ENET_1G_TX_EN */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_DISP_B1_11_ENET_1G_TX_CLK_IO, /* GPIO_DISP_B1_11 is configured as ENET_1G_TX_CLK_IO */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ } /*********************************************************************************************************************** diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/Kconfig new file mode 100755 index 000000000..5753d8854 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/Kconfig @@ -0,0 +1,8 @@ +config BOARD_NETWORK_USE_100M_ENET_PORT + bool "Enable 100M Enet Port" + default y + +config BOARD_NETWORK_USE_1G_ENET_PORT + bool "Enable 1000M Enet Port" + default y + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/Makefile new file mode 100755 index 000000000..1df7f37e7 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := enet_ethernetif.c enet_ethernetif_kinetis.c fsl_enet.c fsl_enet_qos.c +SRC_DIR := phy mdio +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/enet_ethernetif.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/enet_ethernetif.c new file mode 100644 index 000000000..641c66436 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/enet_ethernetif.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * Copyright (c) 2013-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/ethip6.h" +#include "netif/etharp.h" +#include "netif/ppp/pppoe.h" +#include "lwip/igmp.h" +#include "lwip/mld6.h" + +#if USE_RTOS && defined(SDK_OS_FREE_RTOS) +#include "FreeRTOS.h" +#include "event_groups.h" +#endif + +#include "pin_mux.h" +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" +#include "sys_arch.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +static mdio_handle_t mdioHandle = {.ops = &EXAMPLE_MDIO_OPS}; + +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT +static phy_handle_t enet0_phyHandle = {.phyAddr = EXAMPLE_ENET0_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &EXAMPLE_ENET0_PHY_OPS}; +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT +static phy_handle_t enet1_phyHandle = {.phyAddr = EXAMPLE_ENET1_PHY_ADDRESS, .mdioHandle = &mdioHandle, .ops = &EXAMPLE_ENET1_PHY_OPS}; +#endif +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ +void Time_Update_LwIP(void) +{ +} +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT +ethernetif_config_t enet0_cfg = { + .phyHandle = &enet0_phyHandle, + .macAddress = configMAC_ADDR, +}; +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT +ethernetif_config_t enet1_cfg = { + .phyHandle = &enet1_phyHandle, + .macAddress = configMAC_ADDR_ETH1, +}; +#endif + +void *ethernetif_config_enet_set(uint8_t enet_port) +{ + +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT + if(0 == enet_port) { + KPrintf("use 100M enet id[%d]\n",enet_port); + return (void *)&enet0_cfg; + } +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT + if(1 == enet_port) { + KPrintf("use 1000M enet id[%d]\n",enet_port); + return (void *)&enet1_cfg; + } + +#endif + return NULL; +} + +int ETH_BSP_Config(void) +{ + gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; + +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT + + GPIO_PinInit(GPIO9, 11, &gpio_config); + GPIO_PinInit(GPIO8, 21, &gpio_config); + /* Pull up the ENET_INT before RESET. */ + GPIO_WritePinOutput(GPIO9, 11, 1); + GPIO_WritePinOutput(GPIO8, 21, 0); + SDK_DelayAtLeastUs(10000, CLOCK_GetFreq(kCLOCK_CpuClk)); + GPIO_WritePinOutput(GPIO8, 21, 1); + SDK_DelayAtLeastUs(6, CLOCK_GetFreq(kCLOCK_CpuClk)); +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT + + EnableIRQ(ENET_1G_MAC0_Tx_Rx_1_IRQn); + EnableIRQ(ENET_1G_MAC0_Tx_Rx_2_IRQn); +#endif + mdioHandle.resource.csrClock_Hz = EXAMPLE_CLOCK_FREQ; + return 0; +} +void ethernetif_phy_init(struct ethernetif *ethernetif, + const ethernetif_config_t *ethernetifConfig, + phy_speed_t *speed, + phy_duplex_t *duplex) +{ + status_t status; + bool link = false; + bool autonego = false; + uint32_t initWaitCount = 0; + uint32_t autoWaitCount = 0; + phy_config_t phyConfig = { + .phyAddr = ethernetifConfig->phyHandle->phyAddr, + .autoNeg = true, + }; + + ethernetifConfig->phyHandle->mdioHandle->resource.base = *ethernetif_enet_ptr(ethernetif); + + LWIP_PLATFORM_DIAG(("Initializing PHY...")); + + while ((initWaitCount < ENET_ATONEGOTIATION_TIMEOUT) && (!(link && autonego))) + { + status = PHY_Init(ethernetifConfig->phyHandle, &phyConfig); + + + if (kStatus_Success != status) + { + LWIP_ASSERT("\r\nCannot initialize PHY.\r\n", 0); + } + + /* Wait for auto-negotiation success and link up */ + autoWaitCount = ENET_ATONEGOTIATION_TIMEOUT; + do + { + PHY_GetAutoNegotiationStatus(ethernetifConfig->phyHandle, &autonego); + PHY_GetLinkStatus(ethernetifConfig->phyHandle, &link); + if (autonego && link) + { + break; + } + } while (--autoWaitCount); + if (!autonego) + { + LWIP_PLATFORM_DIAG(("PHY Auto-negotiation failed. Please check the cable connection and link partner setting.")); + } + + initWaitCount++; + } + + if (autonego && link) + { + /* Get the actual PHY link speed. */ + PHY_GetLinkSpeedDuplex(ethernetifConfig->phyHandle, speed, duplex); + } +#if 0 /* Disable assert. If initial auto-negation is timeout, \ \ + the ENET is set to default (100Mbs and full-duplex). */ + else + { + LWIP_ASSERT("\r\nGiving up PHY initialization. Please check the ENET cable connection and link partner setting and reset the board.\r\n", 0); + } +#endif +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function ethernetif_linkinput() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void ethernetif_input(struct netif *netif) +{ + struct pbuf *p; + + LWIP_ASSERT("netif != NULL", (netif != NULL)); + + /* move received packet into a new pbuf */ + while ((p = ethernetif_linkinput(netif)) != NULL) + { + /* pass all packets to ethernet_input, which decides what packets it supports */ + if (netif->input(p, netif) != ERR_OK) + { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + pbuf_free(p); + p = NULL; + } + } +} + +void *ethernetif_get_enet_base(const uint8_t enetIdx) +{ + ENET_Type *enets[] = ENET_BASE_PTRS; + int arrayIdx; + int enetCount; + + for (arrayIdx = 0, enetCount = 0; arrayIdx < ARRAY_SIZE(enets); arrayIdx++) + { + if (enets[arrayIdx] != 0U) /* process only defined positions */ + { /* (some SOC headers count ENETs from 1 instead of 0) */ + if (enetCount == enetIdx) + { + return (void *)enets[arrayIdx]; + } + enetCount++; + } + } + + return NULL; +} + +#if defined(FSL_FEATURE_SOC_ENET_QOS_COUNT) && (FSL_FEATURE_SOC_ENET_QOS_COUNT > 0) +void *ethernetif_get_enet_qos_base(const uint8_t enetIdx) +{ + ENET_QOS_Type *enets[] = ENET_QOS_BASE_PTRS; + int arrayIdx; + int enetCount; + + for (arrayIdx = 0, enetCount = 0; arrayIdx < ARRAY_SIZE(enets); arrayIdx++) + { + if (enets[arrayIdx] != 0U) /* process only defined positions */ + { /* (some SOC headers count ENETs from 1 instead of 0) */ + if (enetCount == enetIdx) + { + return (void *)enets[arrayIdx]; + } + enetCount++; + } + } + + return NULL; +} +#endif + +err_t ethernetif_init(struct netif *netif, + struct ethernetif *ethernetif, + void *enetBase, + const ethernetif_config_t *ethernetifConfig) +{ + LWIP_ASSERT("netif != NULL", (netif != NULL)); + LWIP_ASSERT("ethernetifConfig != NULL", (ethernetifConfig != NULL)); + +#if LWIP_NETIF_HOSTNAME + /* Initialize interface hostname */ + netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + + /* + * Initialize the snmp variables and counters inside the struct netif. + * The last argument should be replaced with your link speed, in units + * of bits per second. + */ + MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + + netif->state = ethernetif; + netif->name[0] = IFNAME0; + netif->name[1] = IFNAME1; +/* We directly use etharp_output() here to save a function call. + * You can instead declare your own function an call etharp_output() + * from it if you have to do some checks before sending (e.g. if link + * is available...) */ +#if LWIP_IPV4 + netif->output = etharp_output; +#endif +#if LWIP_IPV6 + netif->output_ip6 = ethip6_output; +#endif /* LWIP_IPV6 */ + netif->linkoutput = ethernetif_linkoutput; + +#if LWIP_IPV4 && LWIP_IGMP + netif_set_igmp_mac_filter(netif, ethernetif_igmp_mac_filter); + netif->flags |= NETIF_FLAG_IGMP; +#endif +#if LWIP_IPV6 && LWIP_IPV6_MLD + netif_set_mld_mac_filter(netif, ethernetif_mld_mac_filter); + netif->flags |= NETIF_FLAG_MLD6; +#endif + + /* Init ethernetif parameters.*/ + *ethernetif_enet_ptr(ethernetif) = enetBase; + LWIP_ASSERT("*ethernetif_enet_ptr(ethernetif) != NULL", (*ethernetif_enet_ptr(ethernetif) != NULL)); + + /* set MAC hardware address length */ + netif->hwaddr_len = ETH_HWADDR_LEN; + + /* set MAC hardware address */ + memcpy(netif->hwaddr, ethernetifConfig->macAddress, NETIF_MAX_HWADDR_LEN); + + /* maximum transfer unit */ + netif->mtu = 1500; /* TODO: define a config */ + + /* device capabilities */ + /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ + netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; + + /* ENET driver initialization.*/ + ethernetif_enet_init(netif, ethernetif, ethernetifConfig); + +#if LWIP_IPV6 && LWIP_IPV6_MLD + /* + * For hardware/netifs that implement MAC filtering. + * All-nodes link-local is handled by default, so we must let the hardware know + * to allow multicast packets in. + * Should set mld_mac_filter previously. */ + if (netif->mld_mac_filter != NULL) + { + ip6_addr_t ip6_allnodes_ll; + ip6_addr_set_allnodes_linklocal(&ip6_allnodes_ll); + netif->mld_mac_filter(netif, &ip6_allnodes_ll, NETIF_ADD_MAC_FILTER); + } +#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */ + + return ERR_OK; +} diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/enet_ethernetif_kinetis.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/enet_ethernetif_kinetis.c new file mode 100644 index 000000000..73de71f57 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/enet_ethernetif_kinetis.c @@ -0,0 +1,721 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * Copyright (c) 2013-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ethip6.h" +#include "lwip/igmp.h" +#include "lwip/mem.h" +#include "lwip/mld6.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" +#include "lwip/stats.h" +#include "lwip/sys.h" +#include "netif/etharp.h" +#include "netif/ppp/pppoe.h" + +#ifdef FSL_RTOS_XIUOS +#define USE_RTOS 1 +#define FSL_RTOS_FREE_RTOS +#endif + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) +#include "FreeRTOS.h" +#include "event_groups.h" +#endif + +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + +#include "fsl_enet.h" +#include "fsl_phy.h" + +#define LWIP_ENET_FLEXIBLE_CONFIGURATION + +/* + * Padding of ethernet frames has to be disabled for zero-copy functionality + * since ENET driver requires the starting buffer addresses to be aligned. + */ +#if ETH_PAD_SIZE != 0 +#error "ETH_PAD_SIZE != 0" +#endif /* ETH_PAD_SIZE != 0 */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +#ifndef ENET_RXBD_NUM + #define ENET_RXBD_NUM (5) +#endif + +#ifndef ENET_TXBD_NUM + #define ENET_TXBD_NUM (3) +#endif + +#ifndef ENET_RXBUFF_SIZE + #define ENET_RXBUFF_SIZE ENET_FRAME_MAX_FRAMELEN +#endif + +#ifndef ENET_TXBUFF_SIZE + #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN) +#endif + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + #if defined(FSL_FEATURE_L2CACHE_LINESIZE_BYTE) \ + && ((!defined(FSL_SDK_DISBLE_L2CACHE_PRESENT)) || (FSL_SDK_DISBLE_L2CACHE_PRESENT == 0)) + #if defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) + #define FSL_CACHE_LINESIZE_MAX MAX(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE, FSL_FEATURE_L2CACHE_LINESIZE_BYTE) + #define FSL_ENET_BUFF_ALIGNMENT MAX(ENET_BUFF_ALIGNMENT, FSL_CACHE_LINESIZE_MAX) + #else + #define FSL_ENET_BUFF_ALIGNMENT MAX(ENET_BUFF_ALIGNMENT, FSL_FEATURE_L2CACHE_LINESIZE_BYTE) + #endif + #elif defined(FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) + #define FSL_ENET_BUFF_ALIGNMENT MAX(ENET_BUFF_ALIGNMENT, FSL_FEATURE_L1DCACHE_LINESIZE_BYTE) + #else + #define FSL_ENET_BUFF_ALIGNMENT ENET_BUFF_ALIGNMENT + #endif +#else + #define FSL_ENET_BUFF_ALIGNMENT ENET_BUFF_ALIGNMENT +#endif + +typedef uint8_t rx_buffer_t[SDK_SIZEALIGN(ENET_RXBUFF_SIZE, FSL_ENET_BUFF_ALIGNMENT)]; +typedef uint8_t tx_buffer_t[SDK_SIZEALIGN(ENET_TXBUFF_SIZE, FSL_ENET_BUFF_ALIGNMENT)]; + +/*! + * @brief Used to wrap received data in a pbuf to be passed into lwIP + * without copying. + * Once last reference is released, RX descriptor will be returned to DMA. + */ +typedef struct rx_pbuf_wrapper +{ + struct pbuf_custom p; /*!< Pbuf wrapper. Has to be first. */ + void *buffer; /*!< Original buffer wrapped by p. */ + struct ethernetif *ethernetif; /*!< Ethernet interface context data. */ +} rx_pbuf_wrapper_t; + +/** + * Helper struct to hold private data used to operate your ethernet interface. + */ +struct ethernetif +{ + ENET_Type *base; +#if (defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0)) || \ + (USE_RTOS && defined(FSL_RTOS_FREE_RTOS)) + enet_handle_t handle; +#endif +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + EventGroupHandle_t enetTransmitAccessEvent; + EventBits_t txFlag; +#endif + enet_rx_bd_struct_t *RxBuffDescrip; + enet_tx_bd_struct_t *TxBuffDescrip; + rx_buffer_t *RxDataBuff; + tx_buffer_t *TxDataBuff; + rx_pbuf_wrapper_t RxPbufs[ENET_RXBD_NUM]; +}; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void ethernetif_rx_release(struct pbuf *p); + +/******************************************************************************* + * Code + ******************************************************************************/ +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) +static void ethernet_callback(ENET_Type *base, + enet_handle_t *handle, +#if FSL_FEATURE_ENET_QUEUE > 1 + uint32_t ringId, +#endif /* FSL_FEATURE_ENET_QUEUE */ + enet_event_t event, + enet_frame_info_t *frameInfo, + void *userData) +{ + struct netif *netif = (struct netif *)userData; + struct ethernetif *ethernetif = netif->state; + BaseType_t xResult; + + + switch (event) + { + case kENET_RxEvent: + ethernetif_input(netif); + break; + case kENET_TxEvent: + { + portBASE_TYPE taskToWake = pdFALSE; + +#ifdef __CA7_REV + if (SystemGetIRQNestingLevel()) +#else + if (__get_IPSR()) +#endif + { + xResult = xEventGroupSetBitsFromISR(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, &taskToWake); + if ((pdPASS == xResult) && (pdTRUE == taskToWake)) + { + portYIELD_FROM_ISR(taskToWake); + } + } + else + { + xEventGroupSetBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag); + } + } + break; + default: + break; + } +} +#endif + +#if LWIP_IPV4 && LWIP_IGMP +err_t ethernetif_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, + enum netif_mac_filter_action action) +{ + struct ethernetif *ethernetif = netif->state; + uint8_t multicastMacAddr[6]; + err_t result; + + multicastMacAddr[0] = 0x01U; + multicastMacAddr[1] = 0x00U; + multicastMacAddr[2] = 0x5EU; + multicastMacAddr[3] = (group->addr >> 8) & 0x7FU; + multicastMacAddr[4] = (group->addr >> 16) & 0xFFU; + multicastMacAddr[5] = (group->addr >> 24) & 0xFFU; + + switch (action) + { + case IGMP_ADD_MAC_FILTER: + /* Adds the ENET device to a multicast group.*/ + ENET_AddMulticastGroup(ethernetif->base, multicastMacAddr); + result = ERR_OK; + break; + case IGMP_DEL_MAC_FILTER: + /* + * Moves the ENET device from a multicast group. + * Since the ENET_LeaveMulticastGroup() could filter out also other + * group addresses having the same hash, the call is commented out. + */ + /* ENET_LeaveMulticastGroup(ethernetif->base, multicastMacAddr); */ + result = ERR_OK; + break; + default: + result = ERR_IF; + break; + } + + return result; +} +#endif + +#if LWIP_IPV6 && LWIP_IPV6_MLD +err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, + enum netif_mac_filter_action action) +{ + struct ethernetif *ethernetif = netif->state; + uint8_t multicastMacAddr[6]; + err_t result; + + multicastMacAddr[0] = 0x33U; + multicastMacAddr[1] = 0x33U; + multicastMacAddr[2] = (group->addr[3]) & 0xFFU; + multicastMacAddr[3] = (group->addr[3] >> 8) & 0xFFU; + multicastMacAddr[4] = (group->addr[3] >> 16) & 0xFFU; + multicastMacAddr[5] = (group->addr[3] >> 24) & 0xFFU; + + switch (action) + { + case NETIF_ADD_MAC_FILTER: + /* Adds the ENET device to a multicast group.*/ + ENET_AddMulticastGroup(ethernetif->base, multicastMacAddr); + result = ERR_OK; + break; + case NETIF_DEL_MAC_FILTER: + /* + * Moves the ENET device from a multicast group. + * Since the ENET_LeaveMulticastGroup() could filter out also other + * group addresses having the same hash, the call is commented out. + */ + /* ENET_LeaveMulticastGroup(ethernetif->base, multicastMacAddr); */ + result = ERR_OK; + break; + default: + result = ERR_IF; + break; + } + + return result; +} +#endif + +/** + * Initializes ENET driver. + */ +void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif, + const ethernetif_config_t *ethernetifConfig) +{ + enet_config_t config; + uint32_t sysClock; + enet_buffer_config_t buffCfg[ENET_RING_NUM]; + phy_speed_t speed; + phy_duplex_t duplex; + int i; + + /* prepare the buffer configuration. */ + buffCfg[0].rxBdNumber = ENET_RXBD_NUM; /* Receive buffer descriptor number. */ + buffCfg[0].txBdNumber = ENET_TXBD_NUM; /* Transmit buffer descriptor number. */ + buffCfg[0].rxBuffSizeAlign = sizeof(rx_buffer_t); /* Aligned receive data buffer size. */ + buffCfg[0].txBuffSizeAlign = sizeof(tx_buffer_t); /* Aligned transmit data buffer size. */ + buffCfg[0].rxBdStartAddrAlign = &(ethernetif->RxBuffDescrip[0]); /* Aligned receive buffer descriptor start address. */ + buffCfg[0].txBdStartAddrAlign = &(ethernetif->TxBuffDescrip[0]); /* Aligned transmit buffer descriptor start address. */ + buffCfg[0].rxBufferAlign = &(ethernetif->RxDataBuff[0][0]); /* Receive data buffer start address. */ + buffCfg[0].txBufferAlign = &(ethernetif->TxDataBuff[0][0]); /* Transmit data buffer start address. */ + buffCfg[0].txFrameInfo = NULL; /* Transmit frame information start address. Set only if using zero-copy transmit. */ + buffCfg[0].rxMaintainEnable = true; /* Receive buffer cache maintain. */ + buffCfg[0].txMaintainEnable = true; /* Transmit buffer cache maintain. */ + + sysClock = ethernetifConfig->phyHandle->mdioHandle->resource.csrClock_Hz; + + ENET_GetDefaultConfig(&config); + config.ringNum = ENET_RING_NUM; +#ifdef LWIP_ENET_FLEXIBLE_CONFIGURATION + extern void BOARD_ENETFlexibleConfigure(enet_config_t *config, uint8_t *hwAddr); + BOARD_ENETFlexibleConfigure(&config, netif->hwaddr); +#endif + + ethernetif_phy_init(ethernetif, ethernetifConfig, &speed, &duplex); + //Followings are configured by BOARD_ENETFlexibleConfigure function. +// config.miiSpeed = (enet_mii_speed_t)speed; +// config.miiDuplex = (enet_mii_duplex_t)duplex; + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + uint32_t instance; + static ENET_Type *const enetBases[] = ENET_BASE_PTRS; + static const IRQn_Type enetTxIrqId[] = ENET_Transmit_IRQS; + /*! @brief Pointers to enet receive IRQ number for each instance. */ + static const IRQn_Type enetRxIrqId[] = ENET_Receive_IRQS; +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /*! @brief Pointers to enet timestamp IRQ number for each instance. */ + static const IRQn_Type enetTsIrqId[] = ENET_1588_Timer_IRQS; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Create the Event for transmit busy release trigger. */ + ethernetif->enetTransmitAccessEvent = xEventGroupCreate(); + ethernetif->txFlag = 0x1; + + config.interrupt |= kENET_RxFrameInterrupt | kENET_TxFrameInterrupt | kENET_TxBufferInterrupt | kENET_LateCollisionInterrupt; + + for (instance = 0; instance < ARRAY_SIZE(enetBases); instance++) + { + if (enetBases[instance] == ethernetif->base) + { +#ifdef __CA7_REV + GIC_SetPriority(enetRxIrqId[instance], ENET_PRIORITY); + GIC_SetPriority(enetTxIrqId[instance], ENET_PRIORITY); +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + GIC_SetPriority(enetTsIrqId[instance], ENET_1588_PRIORITY); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +#else + NVIC_SetPriority(enetRxIrqId[instance], ENET_PRIORITY); + NVIC_SetPriority(enetTxIrqId[instance], ENET_PRIORITY); +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + NVIC_SetPriority(enetTsIrqId[instance], ENET_1588_PRIORITY); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +#endif /* __CA7_REV */ + break; + } + } + + LWIP_ASSERT("Input Ethernet base error!", (instance != ARRAY_SIZE(enetBases))); +#endif /* USE_RTOS */ + + for (i = 0; i < ENET_RXBD_NUM; i++) + { + ethernetif->RxPbufs[i].p.custom_free_function = ethernetif_rx_release; + ethernetif->RxPbufs[i].buffer = &(ethernetif->RxDataBuff[i][0]); + ethernetif->RxPbufs[i].ethernetif = ethernetif; + } + + /* Initialize the ENET module. */ + ENET_Init(ethernetif->base, ðernetif->handle, &config, &buffCfg[0], netif->hwaddr, sysClock); + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + ENET_SetCallback(ðernetif->handle, ethernet_callback, netif); +#endif + + ENET_ActiveRead(ethernetif->base); + +} + +void **ethernetif_enet_ptr(struct ethernetif *ethernetif) +{ + return (void **)&(ethernetif->base); +} + +/** + * Returns next buffer for TX. + * Can wait if no buffer available. + */ +static unsigned char *enet_get_tx_buffer(struct ethernetif *ethernetif) +{ + static unsigned char ucBuffer[ENET_FRAME_MAX_FRAMELEN]; + return ucBuffer; +} + +/** + * Sends frame via ENET. + */ +static err_t enet_send_frame(struct ethernetif *ethernetif, unsigned char *data, const uint32_t length) +{ +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + { + status_t result; + + do + { + result = ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length, 0, false, NULL); + + if (result == kStatus_ENET_TxFrameBusy) + { + xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, pdTRUE, (BaseType_t) false, + portMAX_DELAY); + } + + } while (result == kStatus_ENET_TxFrameBusy); + return ERR_OK; + } +#else + { + uint32_t counter; + + for (counter = ENET_TIMEOUT; counter != 0U; counter--) + { + if (ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length, 0, false, NULL) != kStatus_ENET_TxFrameBusy) + { + return ERR_OK; + } + } + + return ERR_TIMEOUT; + } +#endif +} + +/** + * Reclaims RX buffer held by the p after p is no longer used + * by the application / lwIP. + */ +static void ethernetif_rx_release(struct pbuf *p) +{ + rx_pbuf_wrapper_t *wrapper = (rx_pbuf_wrapper_t *)p; + SYS_ARCH_DECL_PROTECT(old_level); + + SYS_ARCH_PROTECT(old_level); + ENET_ReleaseRxBuffer(wrapper->ethernetif->base, &wrapper->ethernetif->handle, wrapper->buffer, 0); + SYS_ARCH_UNPROTECT(old_level); +} + +/** + * Reads a received frame - wraps its descriptor buffer(s) into a pbuf or a pbuf chain and returns it. + * The descriptors are returned to DMA only once the returned pbuf is released. + * Function can be called only after ENET_GetRxFrameSize() indicates + * that there actually is a received frame. + */ +static struct pbuf *ethernetif_read_frame(struct ethernetif *ethernetif, uint32_t length) +{ + rx_pbuf_wrapper_t *wrapper; + uint32_t len = 0; + uint32_t ts; + struct pbuf *p = NULL; + struct pbuf *q = NULL; + void *buffer; + bool isLastBuff; + status_t status; + int i; + + do + { + status = ENET_GetRxBuffer(ethernetif->base, ðernetif->handle, &buffer, &len, 0, &isLastBuff, &ts); + LWIP_UNUSED_ARG(status); /* for LWIP_NOASSERT */ + LWIP_ASSERT("ENET_GetRxBuffer() status != kStatus_Success", status == kStatus_Success); + + /* Find pbuf wrapper for the actually read byte buffer */ + wrapper = NULL; + for (i = 0; i < ENET_RXBD_NUM; i++) + { + if (buffer == ethernetif->RxPbufs[i].buffer) + { + wrapper = ðernetif->RxPbufs[i]; + break; + } + } + LWIP_ASSERT("Buffer returned by ENET_GetRxBuffer() doesn't match any RX buffer descriptor", wrapper != NULL); + + /* Wrap the receive buffer in pbuf. */ + if (p == NULL) + { + p = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &wrapper->p, buffer, len); + LWIP_ASSERT("pbuf_alloced_custom() failed", p); + } + else + { + q = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &wrapper->p, buffer, len); + LWIP_ASSERT("pbuf_alloced_custom() failed", q); + + pbuf_cat(p, q); + } + } while (!isLastBuff); + + LWIP_ASSERT("p->tot_len != length", p->tot_len == length); + + MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) + { + /* broadcast or multicast packet */ + MIB2_STATS_NETIF_INC(netif, ifinnucastpkts); + } + else + { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifinucastpkts); + } + + LINK_STATS_INC(link.recv); + + return p; +} + +/** + * Drops (releases) receive descriptors until the last one of a frame is reached. + * Function can be called only after ENET_GetRxFrameSize() indicates + * that there actually is a frame error or a received frame. + */ +static void ethernetif_drop_frame(struct ethernetif *ethernetif) +{ + status_t status; + void *buffer; + uint32_t len; + uint32_t ts; + bool isLastBuff; + + do + { +#if 0 /* Error statisctics */ + enet_data_error_stats_t eErrStatic; + /* Get the error information of the received g_frame. */ + ENET_GetRxErrBeforeReadFrame(ðernetif->handle, &eErrStatic); +#endif + status = ENET_GetRxBuffer(ethernetif->base, ðernetif->handle, &buffer, &len, 0, &isLastBuff, &ts); + LWIP_UNUSED_ARG(status); /* for LWIP_NOASSERT */ + LWIP_ASSERT("ENET_GetRxBuffer() status != kStatus_Success", status == kStatus_Success); + ENET_ReleaseRxBuffer(ethernetif->base, ðernetif->handle, buffer, 0); + } while (!isLastBuff); + + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: RxFrameError\n")); + + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); +} + +struct pbuf *ethernetif_linkinput(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p = NULL; + status_t status; + uint32_t len; + + /* Obtain the size of the packet and put it into the "len" variable. */ + status = ENET_GetRxFrameSize(ðernetif->handle, &len, 0); + + if (status == kStatus_Success) + { + /* Read frame. */ + p = ethernetif_read_frame(ethernetif, len); + } + else if (status != kStatus_ENET_RxFrameEmpty) + { + /* Drop the frame when error happened. */ + ethernetif_drop_frame(ethernetif); + } + + return p; +} + +err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p) +{ + err_t result; + struct ethernetif *ethernetif = netif->state; + struct pbuf *q; + unsigned char *pucBuffer; + unsigned char *pucChar; + + LWIP_ASSERT("Output packet buffer empty", p); + + pucBuffer = enet_get_tx_buffer(ethernetif); + if (pucBuffer == NULL) + { + return ERR_BUF; + } + +/* Initiate transfer. */ + +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + + if (p->len == p->tot_len) + { + /* No pbuf chain, don't have to copy -> faster. */ + pucBuffer = (unsigned char *)p->payload; + } + else + { + /* pbuf chain, copy into contiguous ucBuffer. */ + if (p->tot_len > ENET_FRAME_MAX_FRAMELEN) + { + return ERR_BUF; + } + else + { + pucChar = pucBuffer; + + for (q = p; q != NULL; q = q->next) + { + /* Send the data from the pbuf to the interface, one pbuf at a + time. The size of the data in each pbuf is kept in the ->len + variable. */ + /* send data from(q->payload, q->len); */ + memcpy(pucChar, q->payload, q->len); + pucChar += q->len; + } + } + } + + /* Send frame. */ + result = enet_send_frame(ethernetif, pucBuffer, p->tot_len); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((u8_t *)p->payload)[0] & 1) + { + /* broadcast or multicast packet*/ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } + else + { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } +/* increase ifoutdiscards or ifouterrors on error */ + +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.xmit); + + return result; +} + +/** + * Should be called at the beginning of the program to set up the + * first network interface. It calls the function ethernetif_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t ethernetif0_init(struct netif *netif) +{ + static struct ethernetif ethernetif_0; + AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rxBuffDescrip_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t txBuffDescrip_0[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); +// SDK_ALIGN(static rx_buffer_t rxDataBuff_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); +// SDK_ALIGN(static tx_buffer_t txDataBuff_0[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + + AT_NONCACHEABLE_SECTION_ALIGN(static rx_buffer_t rxDataBuff_0[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + AT_NONCACHEABLE_SECTION_ALIGN(static tx_buffer_t txDataBuff_0[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + + ethernetif_0.RxBuffDescrip = &(rxBuffDescrip_0[0]); + ethernetif_0.TxBuffDescrip = &(txBuffDescrip_0[0]); + ethernetif_0.RxDataBuff = &(rxDataBuff_0[0]); + ethernetif_0.TxDataBuff = &(txDataBuff_0[0]); + + return ethernetif_init(netif, ðernetif_0, ethernetif_get_enet_base(0U), (ethernetif_config_t *)netif->state); +} + +#if defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 1) +/** + * Should be called at the beginning of the program to set up the + * second network interface. It calls the function ethernetif_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + * any other err_t on error + */ +err_t ethernetif1_init(struct netif *netif) +{ + static struct ethernetif ethernetif_1; + AT_NONCACHEABLE_SECTION_ALIGN(static enet_rx_bd_struct_t rxBuffDescrip_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + AT_NONCACHEABLE_SECTION_ALIGN(static enet_tx_bd_struct_t txBuffDescrip_1[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); +// SDK_ALIGN(static rx_buffer_t rxDataBuff_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); +// SDK_ALIGN(static tx_buffer_t txDataBuff_1[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + + AT_NONCACHEABLE_SECTION_ALIGN(static rx_buffer_t rxDataBuff_1[ENET_RXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + AT_NONCACHEABLE_SECTION_ALIGN(static tx_buffer_t txDataBuff_1[ENET_TXBD_NUM], FSL_ENET_BUFF_ALIGNMENT); + + ethernetif_1.RxBuffDescrip = &(rxBuffDescrip_1[0]); + ethernetif_1.TxBuffDescrip = &(txBuffDescrip_1[0]); + ethernetif_1.RxDataBuff = &(rxDataBuff_1[0]); + ethernetif_1.TxDataBuff = &(txDataBuff_1[0]); + + return ethernetif_init(netif, ðernetif_1, ethernetif_get_enet_base(1U), (ethernetif_config_t *)netif->state); +} +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/fsl_enet.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/fsl_enet.c new file mode 100644 index 000000000..214a905ef --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/fsl_enet.c @@ -0,0 +1,3929 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include +#include "fsl_enet.h" +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL +#include "fsl_cache.h" +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.enet" +#endif + +/*! @brief Ethernet mac address length. */ +#define ENET_FRAME_MACLEN 6U +/*! @brief MDC frequency. */ +#define ENET_MDC_FREQUENCY 2500000U +/*! @brief NanoSecond in one second. */ +#define ENET_NANOSECOND_ONE_SECOND 1000000000U + +/*! @brief Define the ENET ring/class bumber . */ +enum +{ + kENET_Ring0 = 0U, /*!< ENET ring/class 0. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + kENET_Ring1 = 1U, /*!< ENET ring/class 1. */ + kENET_Ring2 = 2U /*!< ENET ring/class 2. */ +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +}; + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Pointers to enet clocks for each instance. */ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +const clock_ip_name_t s_enetClock[] = ENET_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointers to enet transmit IRQ number for each instance. */ +static const IRQn_Type s_enetTxIrqId[] = ENET_Transmit_IRQS; +/*! @brief Pointers to enet receive IRQ number for each instance. */ +static const IRQn_Type s_enetRxIrqId[] = ENET_Receive_IRQS; +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! @brief Pointers to enet timestamp IRQ number for each instance. */ +static const IRQn_Type s_enetTsIrqId[] = ENET_Ts_IRQS; +/*! @brief Pointers to enet 1588 timestamp IRQ number for each instance. */ +static const IRQn_Type s_enet1588TimerIrqId[] = ENET_1588_Timer_IRQS; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +/*! @brief Pointers to enet error IRQ number for each instance. */ +static const IRQn_Type s_enetErrIrqId[] = ENET_Error_IRQS; + +/*! @brief Pointers to enet bases for each instance. */ +static ENET_Type *const s_enetBases[] = ENET_BASE_PTRS; + +/*! @brief Pointers to enet handles for each instance. */ +static enet_handle_t *s_ENETHandle[ARRAY_SIZE(s_enetBases)]; + +/* ENET ISR for transactional APIs. */ +#if FSL_FEATURE_ENET_QUEUE > 1 +static enet_isr_ring_t s_enetTxIsr[ARRAY_SIZE(s_enetBases)]; +static enet_isr_ring_t s_enetRxIsr[ARRAY_SIZE(s_enetBases)]; +#else +static enet_isr_t s_enetTxIsr[ARRAY_SIZE(s_enetBases)]; +static enet_isr_t s_enetRxIsr[ARRAY_SIZE(s_enetBases)]; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +static enet_isr_t s_enetErrIsr[ARRAY_SIZE(s_enetBases)]; +static enet_isr_t s_enetTsIsr[ARRAY_SIZE(s_enetBases)]; +static enet_isr_t s_enet1588TimerIsr[ARRAY_SIZE(s_enetBases)]; + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Set ENET MAC controller with the configuration. + * + * @param base ENET peripheral base address. + * @param handle The ENET handle pointer. + * @param config ENET Mac configuration. + * @param bufferConfig ENET buffer configuration. + * @param macAddr ENET six-byte mac address. + * @param srcClock_Hz ENET module clock source, normally it's system clock. + */ +static void ENET_SetMacController(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz); + +/*! + * @brief Set ENET handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handle pointer. + * @param config ENET configuration stucture pointer. + * @param bufferConfig ENET buffer configuration. + */ +static void ENET_SetHandler(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint32_t srcClock_Hz); + +/*! + * @brief Set ENET MAC transmit buffer descriptors. + * + * @param handle The ENET handle pointer. + * @param config The ENET configuration structure. + * @param bufferConfig The ENET buffer configuration. + */ +static void ENET_SetTxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig); + +/*! + * @brief Set ENET MAC receive buffer descriptors. + * + * @param handle The ENET handle pointer. + * @param config The ENET configuration structure. + * @param bufferConfig The ENET buffer configuration. + */ +static void ENET_SetRxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig); + +/*! + * @brief Updates the ENET read buffer descriptors. + * + * @param base ENET peripheral base address. + * @param handle The ENET handle pointer. + * @param ringId The descriptor ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + */ +static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId); + +/*! + * @brief Updates index. + */ +static uint16_t ENET_IncreaseIndex(uint16_t index, uint16_t max); + +/*! + * @brief Allocates all Rx buffers in BDs. + */ +static status_t ENET_RxBufferAllocAll(ENET_Type *base, enet_handle_t *handle); + +/*! + * @brief Frees all Rx buffers in BDs. + */ +static void ENET_RxBufferFreeAll(ENET_Type *base, enet_handle_t *handle); + +/******************************************************************************* + * Code + ******************************************************************************/ + +/*! + * @brief Get the ENET instance from peripheral base address. + * + * @param base ENET peripheral base address. + * @return ENET instance. + */ +uint32_t ENET_GetInstance(ENET_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_enetBases); instance++) + { + if (s_enetBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_enetBases)); + + return instance; +} + +/*! + * brief Gets the ENET default configuration structure. + * + * The purpose of this API is to get the default ENET MAC controller + * configure structure for ENET_Init(). User may use the initialized + * structure unchanged in ENET_Init(), or modify some fields of the + * structure before calling ENET_Init(). + * Example: + code + enet_config_t config; + ENET_GetDefaultConfig(&config); + endcode + * param config The ENET mac controller configuration structure pointer. + */ +void ENET_GetDefaultConfig(enet_config_t *config) +{ + /* Checks input parameter. */ + assert(config != NULL); + + /* Initializes the MAC configure structure to zero. */ + (void)memset(config, 0, sizeof(enet_config_t)); + + /* Sets MII mode, full duplex, 100Mbps for MAC and PHY data interface. */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + config->miiMode = kENET_RgmiiMode; +#else + config->miiMode = kENET_RmiiMode; +#endif + config->miiSpeed = kENET_MiiSpeed100M; + config->miiDuplex = kENET_MiiFullDuplex; + + config->ringNum = 1; + + /* Sets the maximum receive frame length. */ + config->rxMaxFrameLen = ENET_FRAME_MAX_FRAMELEN; +} + +/*! + * brief Initializes the ENET module. + * + * This function initializes the module with the ENET configuration. + * note ENET has two buffer descriptors legacy buffer descriptors and + * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To + * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor + * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure() + * to configure the 1588 feature and related buffers after calling ENET_Up(). + * + * param base ENET peripheral base address. + * param handle ENET handler pointer. + * param config ENET mac configuration structure pointer. + * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * param bufferConfig ENET buffer configuration structure pointer. + * The buffer configuration should be prepared for ENET Initialization. + * It is the start address of "ringNum" enet_buffer_config structures. + * To support added multi-ring features in some soc and compatible with the previous + * enet driver version. For single ring supported, this bufferConfig is a buffer + * configure structure pointer, for multi-ring supported and used case, this bufferConfig + * pointer should be a buffer configure structure array pointer. + * param macAddr ENET mac address of Ethernet device. This MAC address should be + * provided. + * param srcClock_Hz The internal module clock source for MII clock. + * retval kStatus_Success Succeed to initialize the ethernet driver. + * retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough. + */ +status_t ENET_Up(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz) +{ + /* Checks input parameters. */ + assert(handle != NULL); + assert(config != NULL); + assert(bufferConfig != NULL); + assert(macAddr != NULL); + assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1); + assert(config->ringNum <= (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + status_t result = kStatus_Success; + + /* Initializes the ENET transmit buffer descriptors. */ + ENET_SetTxBufferDescriptors(handle, config, bufferConfig); + + /* Initializes the ENET receive buffer descriptors. */ + ENET_SetRxBufferDescriptors(handle, config, bufferConfig); + + /* Initializes the ENET MAC controller with basic function. */ + ENET_SetMacController(base, handle, config, bufferConfig, macAddr, srcClock_Hz); + + /* Set all buffers or data in handler for data transmit/receive process. */ + ENET_SetHandler(base, handle, config, bufferConfig, srcClock_Hz); + + /* Allocate buffers for all Rx BDs when zero copy Rx API is needed. */ + if (handle->rxBuffAlloc != NULL) + { + result = ENET_RxBufferAllocAll(base, handle); + } + + return result; +} + +/*! + * brief Initializes the ENET module. + * + * This function ungates the module clock and initializes it with the ENET configuration. + * note ENET has two buffer descriptors legacy buffer descriptors and + * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To + * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor + * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure() + * to configure the 1588 feature and related buffers after calling ENET_Init(). + * + * param base ENET peripheral base address. + * param handle ENET handler pointer. + * param config ENET mac configuration structure pointer. + * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * param bufferConfig ENET buffer configuration structure pointer. + * The buffer configuration should be prepared for ENET Initialization. + * It is the start address of "ringNum" enet_buffer_config structures. + * To support added multi-ring features in some soc and compatible with the previous + * enet driver version. For single ring supported, this bufferConfig is a buffer + * configure structure pointer, for multi-ring supported and used case, this bufferConfig + * pointer should be a buffer configure structure array pointer. + * param macAddr ENET mac address of Ethernet device. This MAC address should be + * provided. + * param srcClock_Hz The internal module clock source for MII clock. + * retval kStatus_Success Succeed to initialize the ethernet driver. + * retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough. + */ +status_t ENET_Init(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz) +{ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + uint32_t instance = ENET_GetInstance(base); + + /* Ungate ENET clock. */ + (void)CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + /* Reset ENET module. */ + ENET_Reset(base); + + return ENET_Up(base, handle, config, bufferConfig, macAddr, srcClock_Hz); +} + +/*! + * brief Stops the ENET module. + + * This function disables the ENET module. + * + * param base ENET peripheral base address. + */ +void ENET_Down(ENET_Type *base) +{ + uint32_t instance = ENET_GetInstance(base); + enet_handle_t *handle = s_ENETHandle[instance]; + + /* Disable interrupt. */ + base->EIMR = 0; + + /* Disable ENET. */ + base->ECR &= ~ENET_ECR_ETHEREN_MASK; + + if (handle->rxBuffFree != NULL) + { + ENET_RxBufferFreeAll(base, handle); + } +} + +/*! + * brief Deinitializes the ENET module. + + * This function gates the module clock, clears ENET interrupts, and disables the ENET module. + * + * param base ENET peripheral base address. + */ +void ENET_Deinit(ENET_Type *base) +{ + ENET_Down(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disables the clock source. */ + (void)CLOCK_DisableClock(s_enetClock[ENET_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * deprecated Do not use this function. It has been superceded by the config param in @ref ENET_Init. + */ +void ENET_SetCallback(enet_handle_t *handle, enet_callback_t callback, void *userData) +{ + assert(handle != NULL); + + /* Set callback and userData. */ + handle->callback = callback; + handle->userData = userData; +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enetRxIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enetRxIrqId[instance]); +} + +void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enetTxIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enetTxIrqId[instance]); +} +#else +void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enetRxIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enetRxIrqId[instance]); +} + +void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enetTxIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enetTxIrqId[instance]); +} +#endif + +void ENET_SetErrISRHandler(ENET_Type *base, enet_isr_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enetErrIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enetErrIrqId[instance]); +} + +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +void ENET_SetTsISRHandler(ENET_Type *base, enet_isr_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enetTsIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enetTsIrqId[instance]); +} + +void ENET_Set1588TimerISRHandler(ENET_Type *base, enet_isr_t ISRHandler) +{ + uint32_t instance = ENET_GetInstance(base); + + s_enet1588TimerIsr[instance] = ISRHandler; + (void)EnableIRQ(s_enet1588TimerIrqId[instance]); +} +#endif + +static void ENET_SetHandler(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint32_t srcClock_Hz) +{ + uint8_t count; + uint32_t instance = ENET_GetInstance(base); + const enet_buffer_config_t *buffCfg = bufferConfig; + + /* Store transfer parameters in handle pointer. */ + (void)memset(handle, 0, sizeof(enet_handle_t)); + + for (count = 0; count < config->ringNum; count++) + { + assert(buffCfg->rxBuffSizeAlign * buffCfg->rxBdNumber > config->rxMaxFrameLen); + + handle->rxBdRing[count].rxBdBase = buffCfg->rxBdStartAddrAlign; + handle->rxBuffSizeAlign[count] = buffCfg->rxBuffSizeAlign; + handle->rxBdRing[count].rxRingLen = buffCfg->rxBdNumber; + handle->rxMaintainEnable[count] = buffCfg->rxMaintainEnable; + handle->txBdRing[count].txBdBase = buffCfg->txBdStartAddrAlign; + handle->txBuffSizeAlign[count] = buffCfg->txBuffSizeAlign; + handle->txBdRing[count].txRingLen = buffCfg->txBdNumber; + handle->txMaintainEnable[count] = buffCfg->txMaintainEnable; + handle->txDirtyRing[count].txDirtyBase = buffCfg->txFrameInfo; + handle->txDirtyRing[count].txRingLen = buffCfg->txBdNumber; + buffCfg++; + } + + handle->ringNum = config->ringNum; + handle->rxBuffAlloc = config->rxBuffAlloc; + handle->rxBuffFree = config->rxBuffFree; + handle->callback = config->callback; + handle->userData = config->userData; +#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID + handle->enetClock = srcClock_Hz; +#endif + + /* Save the handle pointer in the global variables. */ + s_ENETHandle[instance] = handle; + + /* Set the IRQ handler when the interrupt is enabled. */ + if (0U != (config->interrupt & (uint32_t)ENET_TX_INTERRUPT)) + { + ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler); + } + if (0U != (config->interrupt & (uint32_t)ENET_RX_INTERRUPT)) + { + ENET_SetRxISRHandler(base, ENET_ReceiveIRQHandler); + } + if (0U != (config->interrupt & (uint32_t)ENET_ERR_INTERRUPT)) + { + ENET_SetErrISRHandler(base, ENET_ErrorIRQHandler); + } +} + +static void ENET_SetMacController(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz) +{ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1) + { + /* Check the MII mode/speed/duplex setting. */ + if (config->miiSpeed == kENET_MiiSpeed1000M) + { + /* Only RGMII mode has the 1000M bit/s. The 1000M only support full duplex. */ + assert(config->miiMode == kENET_RgmiiMode); + assert(config->miiDuplex == kENET_MiiFullDuplex); + } + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + uint32_t rcr = 0; + uint32_t tcr = 0; + uint32_t ecr = base->ECR; + uint32_t macSpecialConfig = config->macSpecialConfig; + uint32_t maxFrameLen = config->rxMaxFrameLen; + uint32_t configVal = 0; + + /* Maximum frame length check. */ + if (0U != (macSpecialConfig & (uint32_t)kENET_ControlVLANTagEnable)) + { + maxFrameLen = (ENET_FRAME_MAX_FRAMELEN + ENET_FRAME_VLAN_TAGLEN); +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1) + { + if (0U != (macSpecialConfig & (uint32_t)kENET_ControlSVLANEnable)) + { + /* Double vlan tag (SVLAN) supported. */ + maxFrameLen += ENET_FRAME_VLAN_TAGLEN; + } + ecr |= (uint32_t)(((macSpecialConfig & (uint32_t)kENET_ControlSVLANEnable) != 0U) ? + (ENET_ECR_SVLANEN_MASK | ENET_ECR_SVLANDBL_MASK) : + 0U) | + (uint32_t)(((macSpecialConfig & (uint32_t)kENET_ControlVLANUseSecondTag) != 0U) ? + ENET_ECR_VLANUSE2ND_MASK : + 0U); + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + } + + /* Configures MAC receive controller with user configure structure. */ + rcr = ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxPayloadCheckEnable)) ? ENET_RCR_NLC_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) ? ENET_RCR_CFEN_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) ? ENET_RCR_FCE_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxPadRemoveEnable)) ? ENET_RCR_PADEN_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlRxBroadCastRejectEnable)) ? ENET_RCR_BC_REJ_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlPromiscuousEnable)) ? ENET_RCR_PROM_MASK : 0U) | + ENET_RCR_MAX_FL(maxFrameLen) | ENET_RCR_CRCFWD_MASK; + +/* Set the RGMII or RMII, MII mode and control register. */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1) + { + if (config->miiMode == kENET_RgmiiMode) + { + rcr |= ENET_RCR_RGMII_EN_MASK; + } + else + { + rcr &= ~ENET_RCR_RGMII_EN_MASK; + } + + if (config->miiSpeed == kENET_MiiSpeed1000M) + { + ecr |= ENET_ECR_SPEED_MASK; + } + else + { + ecr &= ~ENET_ECR_SPEED_MASK; + } + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + rcr |= ENET_RCR_MII_MODE_MASK; + if (config->miiMode == kENET_RmiiMode) + { + rcr |= ENET_RCR_RMII_MODE_MASK; + } + + /* Speed. */ + if (config->miiSpeed == kENET_MiiSpeed10M) + { + rcr |= ENET_RCR_RMII_10T_MASK; + } + + /* Receive setting for half duplex. */ + if (config->miiDuplex == kENET_MiiHalfDuplex) + { + rcr |= ENET_RCR_DRT_MASK; + } + /* Sets internal loop only for MII mode. */ + if ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlMIILoopEnable)) && + (config->miiMode != kENET_RmiiMode)) + { + rcr |= ENET_RCR_LOOP_MASK; + rcr &= ~ENET_RCR_DRT_MASK; + } + base->RCR = rcr; + + /* Configures MAC transmit controller: duplex mode, mac address insertion. */ + tcr = base->TCR & ~(ENET_TCR_FDEN_MASK | ENET_TCR_ADDINS_MASK); + tcr |= ((kENET_MiiHalfDuplex != config->miiDuplex) ? (uint32_t)ENET_TCR_FDEN_MASK : 0U) | + ((0U != (macSpecialConfig & (uint32_t)kENET_ControlMacAddrInsert)) ? (uint32_t)ENET_TCR_ADDINS_MASK : 0U); + base->TCR = tcr; + + /* Configures receive and transmit accelerator. */ + base->TACC = config->txAccelerConfig; + base->RACC = config->rxAccelerConfig; + + /* Sets the pause duration and FIFO threshold for the flow control enabled case. */ + if (0U != (macSpecialConfig & (uint32_t)kENET_ControlFlowControlEnable)) + { + uint32_t reemReg; + base->OPD = config->pauseDuration; + reemReg = ENET_RSEM_RX_SECTION_EMPTY(config->rxFifoEmptyThreshold); +#if defined(FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD) && FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD + reemReg |= ENET_RSEM_STAT_SECTION_EMPTY(config->rxFifoStatEmptyThreshold); +#endif /* FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD */ + base->RSEM = reemReg; + } + + /* FIFO threshold setting for store and forward enable/disable case. */ + if (0U != (macSpecialConfig & (uint32_t)kENET_ControlStoreAndFwdDisable)) + { + /* Transmit fifo watermark settings. */ + configVal = ((uint32_t)config->txFifoWatermark) & ENET_TFWR_TFWR_MASK; + base->TFWR = configVal; + /* Receive fifo full threshold settings. */ + configVal = ((uint32_t)config->rxFifoFullThreshold) & ENET_RSFL_RX_SECTION_FULL_MASK; + base->RSFL = configVal; + } + else + { + /* Transmit fifo watermark settings. */ + base->TFWR = ENET_TFWR_STRFWD_MASK; + base->RSFL = 0; + } + + /* Enable store and forward when accelerator is enabled */ + if (0U != + (config->txAccelerConfig & ((uint32_t)kENET_TxAccelIpCheckEnabled | (uint32_t)kENET_TxAccelProtoCheckEnabled))) + { + base->TFWR = ENET_TFWR_STRFWD_MASK; + } + if (0U != ((config->rxAccelerConfig & + ((uint32_t)kENET_RxAccelIpCheckEnabled | (uint32_t)kENET_RxAccelProtoCheckEnabled)))) + { + base->RSFL = 0; + } + +/* Initializes the ring 0. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + base->TDSR = MEMORY_ConvertMemoryMapAddress((uint32_t)bufferConfig->txBdStartAddrAlign, kMEMORY_Local2DMA); + base->RDSR = MEMORY_ConvertMemoryMapAddress((uint32_t)bufferConfig->rxBdStartAddrAlign, kMEMORY_Local2DMA); +#else + base->TDSR = (uint32_t)bufferConfig->txBdStartAddrAlign; + base->RDSR = (uint32_t)bufferConfig->rxBdStartAddrAlign; +#endif + base->MRBR = (uint32_t)bufferConfig->rxBuffSizeAlign; + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1) + { + const enet_buffer_config_t *buffCfg = bufferConfig; + + if (config->ringNum > 1U) + { + /* Initializes the ring 1. */ + buffCfg++; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + base->TDSR1 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA); + base->RDSR1 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA); +#else + base->TDSR1 = (uint32_t)buffCfg->txBdStartAddrAlign; + base->RDSR1 = (uint32_t)buffCfg->rxBdStartAddrAlign; +#endif + base->MRBR1 = (uint32_t)buffCfg->rxBuffSizeAlign; + /* Enable the DMAC for ring 1 and with no rx classification set. */ + base->DMACFG[0] = ENET_DMACFG_DMA_CLASS_EN_MASK; + } + if (config->ringNum > 2U) + { + /* Initializes the ring 2. */ + buffCfg++; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + base->TDSR2 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBdStartAddrAlign, kMEMORY_Local2DMA); + base->RDSR2 = MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBdStartAddrAlign, kMEMORY_Local2DMA); +#else + base->TDSR2 = (uint32_t)buffCfg->txBdStartAddrAlign; + base->RDSR2 = (uint32_t)buffCfg->rxBdStartAddrAlign; +#endif + base->MRBR2 = (uint32_t)buffCfg->rxBuffSizeAlign; + /* Enable the DMAC for ring 2 and with no rx classification set. */ + base->DMACFG[1] = ENET_DMACFG_DMA_CLASS_EN_MASK; + } + + /* Defaulting the class/ring 1 and 2 are not enabled and the receive classification is disabled + * so we set the default transmit scheme with the round-robin mode. Beacuse the legacy bd mode + * only supports the round-robin mode. If the avb feature is required, just call the setup avb + * feature API. */ + base->QOS |= ENET_QOS_TX_SCHEME(1); + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + /* Configures the Mac address. */ + ENET_SetMacAddr(base, macAddr); + + /* Initialize the SMI if uninitialized. */ + if (!ENET_GetSMI(base)) + { + ENET_SetSMI(base, srcClock_Hz, + ((0U != (config->macSpecialConfig & (uint32_t)kENET_ControlSMIPreambleDisable)) ? true : false)); + } + +/* Enables Ethernet interrupt, enables the interrupt coalsecing if it is required. */ +#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE + uint8_t queue = 0; + + if (NULL != config->intCoalesceCfg) + { + uint32_t intMask = (ENET_EIMR_TXB_MASK | ENET_EIMR_RXB_MASK); + +#if FSL_FEATURE_ENET_QUEUE > 1 + if (FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) > 1) + { + intMask |= ENET_EIMR_TXB2_MASK | ENET_EIMR_RXB2_MASK | ENET_EIMR_TXB1_MASK | ENET_EIMR_RXB1_MASK; + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + /* Clear all buffer interrupts. */ + base->EIMR &= ~intMask; + + /* Set the interrupt coalescence. */ + for (queue = 0; queue < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base); queue++) + { + base->TXIC[queue] = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[queue]) | + config->intCoalesceCfg->txCoalesceTimeCount[queue] | ENET_TXIC_ICCS_MASK | + ENET_TXIC_ICEN_MASK; + base->RXIC[queue] = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[queue]) | + config->intCoalesceCfg->rxCoalesceTimeCount[queue] | ENET_RXIC_ICCS_MASK | + ENET_RXIC_ICEN_MASK; + } + } +#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */ + ENET_EnableInterrupts(base, config->interrupt); + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Sets the 1588 enhanced feature. */ + ecr |= ENET_ECR_EN1588_MASK; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + /* Enables Ethernet module after all configuration except the buffer descriptor active. */ + ecr |= ENET_ECR_ETHEREN_MASK | ENET_ECR_DBSWP_MASK; + base->ECR = ecr; +} + +static void ENET_SetTxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig) +{ + assert(config != NULL); + assert(bufferConfig != NULL); + + /* Default single ring is supported. */ + uint8_t ringNum; + uint16_t count; + uint32_t txBuffSizeAlign; + uint8_t *txBuffer = NULL; + const enet_buffer_config_t *buffCfg = bufferConfig; + + /* Check the input parameters. */ + for (ringNum = 0; ringNum < config->ringNum; ringNum++) + { + if (buffCfg->txBdStartAddrAlign != NULL) + { + volatile enet_tx_bd_struct_t *curBuffDescrip = buffCfg->txBdStartAddrAlign; + txBuffSizeAlign = buffCfg->txBuffSizeAlign; + + if (buffCfg->txBufferAlign != NULL) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + txBuffer = + (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->txBufferAlign, kMEMORY_Local2DMA); +#else + txBuffer = buffCfg->txBufferAlign; +#endif + } + + for (count = 0; count < buffCfg->txBdNumber; count++) + { + if (buffCfg->txBufferAlign != NULL) + { + /* Set data buffer address. */ + curBuffDescrip->buffer = (uint8_t *)((uint32_t)&txBuffer[count * txBuffSizeAlign]); + } + /* Initializes data length. */ + curBuffDescrip->length = 0; + /* Sets the crc. */ + curBuffDescrip->control = ENET_BUFFDESCRIPTOR_TX_TRANMITCRC_MASK; + /* Sets the last buffer descriptor with the wrap flag. */ + if (count == (buffCfg->txBdNumber - 1U)) + { + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_WRAP_MASK; + } + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Enable transmit interrupt for store the transmit timestamp. */ + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK; +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + /* Set the type of the frame when the credit-based scheme is used. */ + curBuffDescrip->controlExtend1 |= (uint16_t)(ENET_BD_FTYPE(ringNum)); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + /* Increase the index. */ + curBuffDescrip++; + } + } + buffCfg++; + } +} + +static void ENET_SetRxBufferDescriptors(enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig) +{ + assert(config != NULL); + assert(bufferConfig != NULL); + + /* Default single ring is supported. */ + uint8_t ringNum; + uint16_t count; + uint16_t rxBuffSizeAlign; + uint8_t *rxBuffer; + const enet_buffer_config_t *buffCfg = bufferConfig; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint32_t mask = ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Check the input parameters. */ + for (ringNum = 0; ringNum < config->ringNum; ringNum++) + { + assert(buffCfg->rxBuffSizeAlign >= ENET_RX_MIN_BUFFERSIZE); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +#if FSL_FEATURE_ENET_QUEUE > 1 + if (ringNum == 1U) + { + mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt); + } + else if (ringNum == 2U) + { + mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt); + } + else + { + /* Intentional empty */ + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + if ((buffCfg->rxBdStartAddrAlign != NULL) && ((buffCfg->rxBufferAlign != NULL) || config->rxBuffAlloc != NULL)) + { + volatile enet_rx_bd_struct_t *curBuffDescrip = buffCfg->rxBdStartAddrAlign; + rxBuffSizeAlign = buffCfg->rxBuffSizeAlign; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + rxBuffer = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBufferAlign, kMEMORY_Local2DMA); +#else + rxBuffer = buffCfg->rxBufferAlign; +#endif + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (buffCfg->rxMaintainEnable) + { + /* Invalidate rx buffers before DMA transfer data into them. */ + DCACHE_InvalidateByRange((uint32_t)rxBuffer, ((uint32_t)buffCfg->rxBdNumber * rxBuffSizeAlign)); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + for (count = 0; count < buffCfg->rxBdNumber; count++) + { + /* Set data buffer and the length. */ + curBuffDescrip->length = 0; + if (config->rxBuffAlloc == NULL) + { + curBuffDescrip->buffer = (uint8_t *)((uint32_t)&rxBuffer[count * rxBuffSizeAlign]); + /* Initializes the buffer descriptors with empty bit. */ + curBuffDescrip->control = ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + } + + /* Sets the last buffer descriptor with the wrap flag. */ + if (count == (buffCfg->rxBdNumber - 1U)) + { + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (0U != (config->interrupt & mask)) + { + /* Enable receive interrupt. */ + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_RX_INTERRUPT_MASK; + } + else + { + curBuffDescrip->controlExtend1 = 0; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + /* Increase the index. */ + curBuffDescrip++; + } + } + buffCfg++; + } +} + +/*! + * brief Allocates all Rx buffers in BDs. + */ +static status_t ENET_RxBufferAllocAll(ENET_Type *base, enet_handle_t *handle) +{ + assert(handle->rxBuffAlloc != NULL); + + enet_rx_bd_ring_t *rxBdRing; + volatile enet_rx_bd_struct_t *curBuffDescrip; + uint16_t index; + void *buffer; + uint16_t ringId; + + /* Allocate memory for all empty buffers in buffer descriptor */ + for (ringId = 0; ringId < handle->ringNum; ringId++) + { + assert(handle->rxBdRing[ringId].rxBdBase != NULL); + + rxBdRing = &handle->rxBdRing[ringId]; + curBuffDescrip = rxBdRing->rxBdBase; + index = 0; + + do + { + buffer = handle->rxBuffAlloc(base, handle->userData, ringId); + if (buffer == NULL) + { + ENET_RxBufferFreeAll(base, handle); + return kStatus_ENET_InitMemoryFail; + } + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + /* Invalidate cache in case any unfinished cache operation occurs. */ + DCACHE_InvalidateByRange((uint32_t)(uint32_t *)buffer, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffer = + (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)buffer, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + curBuffDescrip->buffer = (uint8_t *)(uint32_t *)buffer; + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increase the buffer descriptor, if it's the last one, increase to first one of the ring. */ + index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + index; + } while (index != 0U); + } + return kStatus_Success; +} + +/*! + * brief Frees all Rx buffers in BDs. + */ +static void ENET_RxBufferFreeAll(ENET_Type *base, enet_handle_t *handle) +{ + assert(handle->rxBuffFree != NULL); + + uint16_t index; + enet_rx_bd_ring_t *rxBdRing; + volatile enet_rx_bd_struct_t *curBuffDescrip; + void *buffer; + uint16_t ringId; + + for (ringId = 0; ringId < handle->ringNum; ringId++) + { + assert(handle->rxBdRing[ringId].rxBdBase != NULL); + + rxBdRing = &handle->rxBdRing[ringId]; + curBuffDescrip = rxBdRing->rxBdBase; + index = 0; + + /* Free memory for all buffers in buffer descriptor */ + do + { + if (curBuffDescrip->buffer != NULL) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffer = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, + kMEMORY_DMA2Local); +#else + buffer = curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + handle->rxBuffFree(base, buffer, handle->userData, ringId); + curBuffDescrip->buffer = NULL; + /* Clears status. */ + curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + + /* Increase the buffer descriptor, if it's the last one, increase to first one of the ring. */ + index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + index; + } while (index != 0U); + } +} + +/*! + * brief Activates frame reception for specified ring. + * + * This function is to active the enet read process for specified ring. + * note This must be called after the MAC configuration and + * state are ready. It must be called after the ENET_Init() and + * ENET_Ptp1588Configure(). This should be called when the ENET receive required. + * + * param base ENET peripheral base address. + * param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + */ +static inline void ENET_ActiveReadRing(ENET_Type *base, uint8_t ringId) +{ + assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + /* Ensure previous data update is completed with Data Synchronization Barrier before activing Rx BD. */ + __DSB(); + + /* Actives the receive buffer descriptor. */ + switch (ringId) + { + case kENET_Ring0: + base->RDAR = ENET_RDAR_RDAR_MASK; + break; +#if FSL_FEATURE_ENET_QUEUE > 1 + case kENET_Ring1: + base->RDAR1 = ENET_RDAR1_RDAR_MASK; + break; + case kENET_Ring2: + base->RDAR2 = ENET_RDAR2_RDAR_MASK; + break; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + default: + assert(false); + break; + } +} + +/*! + * brief Activates frame sending for specified ring. + * note This must be called after the MAC configuration and + * state are ready. It must be called after the ENET_Init() and + * this should be called when the ENET receive required. + * + * param base ENET peripheral base address. + * param ringId The descriptor ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + * + */ +static void ENET_ActiveSendRing(ENET_Type *base, uint8_t ringId) +{ + assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + volatile uint32_t *txDesActive = NULL; + + /* Ensure previous data update is completed with Data Synchronization Barrier before activing Tx BD. */ + __DSB(); + + switch (ringId) + { + case kENET_Ring0: + txDesActive = &(base->TDAR); + break; +#if FSL_FEATURE_ENET_QUEUE > 1 + case kENET_Ring1: + txDesActive = &(base->TDAR1); + break; + case kENET_Ring2: + txDesActive = &(base->TDAR2); + break; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + default: + txDesActive = &(base->TDAR); + break; + } + +#if defined(FSL_FEATURE_ENET_HAS_ERRATA_007885) && FSL_FEATURE_ENET_HAS_ERRATA_007885 + /* There is a TDAR race condition for mutliQ when the software sets TDAR + * and the UDMA clears TDAR simultaneously or in a small window (2-4 cycles). + * This will cause the udma_tx and udma_tx_arbiter state machines to hang. + * Software workaround: introduces a delay by reading the relevant ENET_TDARn_TDAR 4 times + */ + for (uint8_t i = 0; i < 4U; i++) + { + if (*txDesActive == 0U) + { + break; + } + } +#endif + + /* Write to active tx descriptor */ + *txDesActive = 0; +} + +/*! + * brief Sets the ENET MII speed and duplex. + * + * This API is provided to dynamically change the speed and dulpex for MAC. + * + * param base ENET peripheral base address. + * param speed The speed of the RMII mode. + * param duplex The duplex of the RMII mode. + */ +void ENET_SetMII(ENET_Type *base, enet_mii_speed_t speed, enet_mii_duplex_t duplex) +{ + uint32_t rcr = base->RCR; + uint32_t tcr = base->TCR; + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (FSL_FEATURE_ENET_INSTANCE_HAS_AVBn(base) == 1) + { + uint32_t ecr = base->ECR; + + if (kENET_MiiSpeed1000M == speed) + { + assert(duplex == kENET_MiiFullDuplex); + ecr |= ENET_ECR_SPEED_MASK; + } + else + { + ecr &= ~ENET_ECR_SPEED_MASK; + } + + base->ECR = ecr; + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + /* Sets speed mode. */ + if (kENET_MiiSpeed10M == speed) + { + rcr |= ENET_RCR_RMII_10T_MASK; + } + else + { + rcr &= ~ENET_RCR_RMII_10T_MASK; + } + /* Set duplex mode. */ + if (duplex == kENET_MiiHalfDuplex) + { + rcr |= ENET_RCR_DRT_MASK; + tcr &= ~ENET_TCR_FDEN_MASK; + } + else + { + rcr &= ~ENET_RCR_DRT_MASK; + tcr |= ENET_TCR_FDEN_MASK; + } + + base->RCR = rcr; + base->TCR = tcr; +} + +/*! + * brief Sets the ENET module Mac address. + * + * param base ENET peripheral base address. + * param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + */ +void ENET_SetMacAddr(ENET_Type *base, uint8_t *macAddr) +{ + uint32_t address; + + /* Set physical address lower register. */ + address = (uint32_t)(((uint32_t)macAddr[0] << 24U) | ((uint32_t)macAddr[1] << 16U) | ((uint32_t)macAddr[2] << 8U) | + (uint32_t)macAddr[3]); + base->PALR = address; + /* Set physical address high register. */ + address = (uint32_t)(((uint32_t)macAddr[4] << 8U) | ((uint32_t)macAddr[5])); + base->PAUR = address << ENET_PAUR_PADDR2_SHIFT; +} + +/*! + * brief Gets the ENET module Mac address. + * + * param base ENET peripheral base address. + * param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + */ +void ENET_GetMacAddr(ENET_Type *base, uint8_t *macAddr) +{ + assert(macAddr != NULL); + + uint32_t address; + + /* Get from physical address lower register. */ + address = base->PALR; + macAddr[0] = 0xFFU & (uint8_t)(address >> 24U); + macAddr[1] = 0xFFU & (uint8_t)(address >> 16U); + macAddr[2] = 0xFFU & (uint8_t)(address >> 8U); + macAddr[3] = 0xFFU & (uint8_t)address; + + /* Get from physical address high register. */ + address = (base->PAUR & ENET_PAUR_PADDR2_MASK) >> ENET_PAUR_PADDR2_SHIFT; + macAddr[4] = 0xFFU & (uint8_t)(address >> 8U); + macAddr[5] = 0xFFU & (uint8_t)address; +} + +/*! + * brief Sets the ENET SMI(serial management interface)- MII management interface. + * + * param base ENET peripheral base address. + * param srcClock_Hz This is the ENET module clock frequency. See clock distribution. + * param isPreambleDisabled The preamble disable flag. + * - true Enables the preamble. + * - false Disables the preamble. + */ +void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled) +{ + /* Due to bits limitation of SPEED and HOLDTIME, srcClock_Hz must ensure MDC <= 2.5M and holdtime >= 10ns. */ + assert((srcClock_Hz != 0U) && (srcClock_Hz <= 320000000U)); + + uint32_t clkCycle = 0; + uint32_t speed = 0; + uint32_t mscr = 0; + + /* Use (param + N - 1) / N to increase accuracy with rounding. */ + /* Calculate the MII speed which controls the frequency of the MDC. */ + speed = (srcClock_Hz + 2U * ENET_MDC_FREQUENCY - 1U) / (2U * ENET_MDC_FREQUENCY) - 1U; + /* Calculate the hold time on the MDIO output. */ + clkCycle = (10U + ENET_NANOSECOND_ONE_SECOND / srcClock_Hz - 1U) / (ENET_NANOSECOND_ONE_SECOND / srcClock_Hz) - 1U; + /* Build the configuration for MDC/MDIO control. */ + mscr = + ENET_MSCR_MII_SPEED(speed) | ENET_MSCR_HOLDTIME(clkCycle) | (isPreambleDisabled ? ENET_MSCR_DIS_PRE_MASK : 0U); + base->MSCR = mscr; +} + +/*! + * brief Starts an SMI write command. + * + * Used for standard IEEE802.3 MDIO Clause 22 format. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. Range from 0 ~ 31. + * param operation The write operation. + * param data The data written to PHY. + */ +void ENET_StartSMIWrite(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_write_t operation, uint32_t data) +{ + uint32_t mmfr = 0; + + /* Build MII write command. */ + mmfr = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | + ENET_MMFR_TA(2U) | (data & 0xFFFFU); + base->MMFR = mmfr; +} + +/*! + * brief Starts an SMI (Serial Management Interface) read command. + * + * Used for standard IEEE802.3 MDIO Clause 22 format. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. Range from 0 ~ 31. + * param operation The read operation. + */ +void ENET_StartSMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_read_t operation) +{ + uint32_t mmfr = 0; + + /* Build MII read command. */ + mmfr = ENET_MMFR_ST(1U) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | ENET_MMFR_TA(2U); + base->MMFR = mmfr; +} + +#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write register command. + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIWriteReg(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU); + uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU); + + /* Address write. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiAddrWrite_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(regAddr); + base->MMFR = mmfr; +} + +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write data command. + * + * After writing MMFR register, we need to check whether the transmission is over. + * This is an example for whole precedure of clause 45 MDIO write. + * code + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteData(base, phyAddr, phyReg, data); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * endcode + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + * param data The data written to PHY. + */ +void ENET_StartExtC45SMIWriteData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU); + + /* Build MII write command. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiWriteFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2) | ENET_MMFR_DATA(data); + base->MMFR = mmfr; +} + +/*! + * brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI read data command. + * + * After writing MMFR register, we need to check whether the transmission is over. + * This is an example for whole precedure of clause 45 MDIO read. + * code + * uint32_t data; + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIReadData(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * data = ENET_ReadSMIData(base); + * endcode + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIReadData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (uint16_t)((phyReg >> 16U) & 0x1FU); + + /* Build MII read command. */ + mmfr = ENET_MMFR_ST(0) | ENET_MMFR_OP(kENET_MiiReadFrame_C45) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(devAddr) | + ENET_MMFR_TA(2); + base->MMFR = mmfr; +} +#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */ + +static uint16_t ENET_IncreaseIndex(uint16_t index, uint16_t max) +{ + assert(index < max); + + /* Increase the index. */ + index++; + if (index >= max) + { + index = 0; + } + return index; +} + +static inline bool ENET_TxDirtyRingAvailable(enet_tx_dirty_ring_t *txDirtyRing) +{ + return !txDirtyRing->isFull; +} + +/*! + * brief Gets the error statistics of a received frame for ENET specified ring. + * + * This API must be called after the ENET_GetRxFrameSize and before the ENET_ReadFrame(). + * If the ENET_GetRxFrameSize returns kStatus_ENET_RxFrameError, + * the ENET_GetRxErrBeforeReadFrame can be used to get the exact error statistics. + * This is an example. + * code + * status = ENET_GetRxFrameSize(&g_handle, &length, 0); + * if (status == kStatus_ENET_RxFrameError) + * { + * ENET_GetRxErrBeforeReadFrame(&g_handle, &eErrStatic, 0); + * ENET_ReadFrame(EXAMPLE_ENET, &g_handle, NULL, 0); + * } + * endcode + * param handle The ENET handler structure pointer. This is the same handler pointer used in the ENET_Init. + * param eErrorStatic The error statistics structure pointer. + * param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + */ +void ENET_GetRxErrBeforeReadFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId) +{ + assert(handle != NULL); + assert(eErrorStatic != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + uint16_t control = 0; + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + volatile enet_rx_bd_struct_t *cmpBuffDescrip = curBuffDescrip; + + do + { + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + control = curBuffDescrip->control; + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK)) + { + /* The receive truncate error. */ + eErrorStatic->statsRxTruncateErr++; + } + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK)) + { + /* The receive over run error. */ + eErrorStatic->statsRxOverRunErr++; + } + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK)) + { + /* The receive length violation error. */ + eErrorStatic->statsRxLenGreaterErr++; + } + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK)) + { + /* The receive alignment error. */ + eErrorStatic->statsRxAlignErr++; + } + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_CRC_MASK)) + { + /* The receive CRC error. */ + eErrorStatic->statsRxFcsErr++; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint16_t controlExt = curBuffDescrip->controlExtend1; + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_MACERR_MASK)) + { + /* The MAC error. */ + eErrorStatic->statsRxMacErr++; + } + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK)) + { + /* The PHY error. */ + eErrorStatic->statsRxPhyErr++; + } + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK)) + { + /* The receive collision error. */ + eErrorStatic->statsRxCollisionErr++; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + break; + } + + /* Increase the buffer descriptor, if it's the last one, increase to first one of the ring buffer. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + curBuffDescrip = rxBdRing->rxBdBase; + } + else + { + curBuffDescrip++; + } + + } while (curBuffDescrip != cmpBuffDescrip); +} + +/*! + * brief Gets statistical data in transfer. + * + * param base ENET peripheral base address. + * param statistics The statistics structure pointer. + */ +void ENET_GetStatistics(ENET_Type *base, enet_transfer_stats_t *statistics) +{ + /* Rx statistics */ + statistics->statsRxFrameCount = base->RMON_R_PACKETS; + statistics->statsRxFrameOk = base->IEEE_R_FRAME_OK; + statistics->statsRxCrcErr = base->IEEE_R_CRC; + statistics->statsRxAlignErr = base->IEEE_R_ALIGN; + statistics->statsRxDropInvalidSFD = base->IEEE_R_DROP; + statistics->statsRxFifoOverflowErr = base->IEEE_R_MACERR; + + /* Tx statistics */ + statistics->statsTxFrameCount = base->RMON_T_PACKETS; + statistics->statsTxFrameOk = base->IEEE_T_FRAME_OK; + statistics->statsTxCrcAlignErr = base->RMON_T_CRC_ALIGN; + statistics->statsTxFifoUnderRunErr = base->IEEE_T_MACERR; +} + +/*! + * brief Gets the size of the read frame for specified ring. + * + * This function gets a received frame size from the ENET buffer descriptors. + * note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS. + * After calling ENET_GetRxFrameSize, ENET_ReadFrame() should be called to receive frame and update the BD + * if the result is not "kStatus_ENET_RxFrameEmpty". + * + * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * param length The length of the valid frame received. + * param ringId The ring index or ring number. + * retval kStatus_ENET_RxFrameEmpty No frame received. Should not call ENET_ReadFrame to read frame. + * retval kStatus_ENET_RxFrameError Data error happens. ENET_ReadFrame should be called with NULL data + * and NULL length to update the receive buffers. + * retval kStatus_Success Receive a frame Successfully then the ENET_ReadFrame + * should be called with the right data buffer and the captured data length input. + */ +status_t ENET_GetRxFrameSize(enet_handle_t *handle, uint32_t *length, uint8_t ringId) +{ + assert(handle != NULL); + assert(length != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + /* Reset the length to zero. */ + *length = 0; + + uint16_t validLastMask = ENET_BUFFDESCRIPTOR_RX_LAST_MASK | ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + uint16_t index = rxBdRing->rxGenIdx; + bool isReturn = false; + status_t result = kStatus_Success; + + /* Check the current buffer descriptor's empty flag. If empty means there is no frame received. */ + /* If this buffer descriptor is owned by application, return empty. Only need to check the first BD's owner if one + * frame in mutiple BDs. */ + if (0U != (curBuffDescrip->control & (ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK | ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK))) + { + isReturn = true; + result = kStatus_ENET_RxFrameEmpty; + } + else + { + do + { + /* Add check for abnormal case. */ + if (curBuffDescrip->length == 0U) + { + isReturn = true; + result = kStatus_ENET_RxFrameError; + break; + } + + /* Find the last buffer descriptor. */ + if ((curBuffDescrip->control & validLastMask) == ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + isReturn = true; + /* The last buffer descriptor in the frame check the status of the received frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK)) + { + result = kStatus_ENET_RxFrameError; + break; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (0U != (curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK)) + { + result = kStatus_ENET_RxFrameError; + break; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* FCS is removed by MAC. */ + *length = curBuffDescrip->length; + break; + } + /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */ + index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + index; + } while (index != rxBdRing->rxGenIdx); + } + + if (isReturn == false) + { + /* The frame is on processing - set to empty status to make application to receive it next time. */ + result = kStatus_ENET_RxFrameEmpty; + } + + return result; +} + +/*! + * brief Reads a frame from the ENET device. + * This function reads a frame (both the data and the length) from the ENET buffer descriptors. + * User can get timestamp through ts pointer if the ts is not NULL. + * note It doesn't store the timestamp in the receive timestamp queue. + * The ENET_GetRxFrameSize should be used to get the size of the prepared data buffer. + * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer + * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time + * consumption. + * This is an example: + * code + * uint32_t length; + * enet_handle_t g_handle; + * Comments: Get the received frame size firstly. + * status = ENET_GetRxFrameSize(&g_handle, &length, 0); + * if (length != 0) + * { + * Comments: Allocate memory here with the size of "length" + * uint8_t *data = memory allocate interface; + * if (!data) + * { + * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL); + * Comments: Add the console warning log. + * } + * else + * { + * status = ENET_ReadFrame(ENET, &g_handle, data, length, 0, NULL); + * Comments: Call stack input API to deliver the data to stack + * } + * } + * else if (status == kStatus_ENET_RxFrameError) + * { + * Comments: Update the received buffer when a error frame is received. + * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL); + * } + * endcode + * param base ENET peripheral base address. + * param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * param data The data buffer provided by user to store the frame which memory size should be at least "length". + * param length The size of the data buffer which is still the length of the received frame. + * param ringId The ring index or ring number. + * param ts The timestamp address to store received timestamp. + * return The execute status, successful or failure. + */ +status_t ENET_ReadFrame( + ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint8_t ringId, uint32_t *ts) +{ + assert(handle != NULL); + assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + uint32_t len = 0; + uint32_t offset = 0; + uint16_t control; + bool isLastBuff = false; + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + uint16_t index = rxBdRing->rxGenIdx; + status_t result = kStatus_Success; + uint32_t address; + uint32_t dest; + + /* For data-NULL input, only update the buffer descriptor. */ + if (data == NULL) + { + do + { + /* Update the control flag. */ + control = curBuffDescrip->control; + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + + /* Find the last buffer descriptor for the frame. */ + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + break; + } + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } while (index != rxBdRing->rxGenIdx); + } + else + { + while (!isLastBuff) + { +/* A frame on one buffer or several receive buffers are both considered. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + dest = (uint32_t)data + offset; + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + /* This is a valid frame. */ + isLastBuff = true; + if (length == curBuffDescrip->length) + { + /* Copy the frame to user's buffer without FCS. */ + len = curBuffDescrip->length - offset; + (void)memcpy((void *)(uint32_t *)dest, (void *)(uint32_t *)address, len); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Get the timestamp if the ts isn't NULL. */ + if (ts != NULL) + { + *ts = curBuffDescrip->timestamp; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + break; + } + else + { + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + } + } + else + { + /* Store a frame on several buffer descriptors. */ + isLastBuff = false; + /* Length check. */ + if (offset >= length) + { + result = kStatus_ENET_RxFrameFail; + break; + } + (void)memcpy((void *)(uint32_t *)dest, (void *)(uint32_t *)address, handle->rxBuffSizeAlign[ringId]); + offset += handle->rxBuffSizeAlign[ringId]; + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + } + + /* Get the current buffer descriptor. */ + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } + } + + return result; +} + +static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint8_t ringId) +{ + assert(handle != NULL); + assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + + /* Clears status. */ + curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increase current buffer descriptor to the next one. */ + rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + + ENET_ActiveReadRing(base, ringId); +} + +/*! + * brief Transmits an ENET frame for specified ring. + * note The CRC is automatically appended to the data. Input the data to send without the CRC. + * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer + * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time + * consumption. + * + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * param data The data buffer provided by user to send. + * param length The length of the data to send. + * param ringId The ring index or ring number. + * param tsFlag Timestamp enable flag. + * param context Used by user to handle some events after transmit over. + * retval kStatus_Success Send frame succeed. + * retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission. + * The transmit busy happens when the data send rate is over the MAC capacity. + * The waiting mechanism is recommended to be added after each call return with + * kStatus_ENET_TxFrameBusy. + */ +status_t ENET_SendFrame(ENET_Type *base, + enet_handle_t *handle, + const uint8_t *data, + uint32_t length, + uint8_t ringId, + bool tsFlag, + void *context) +{ + assert(handle != NULL); + assert(data != NULL); + assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + volatile enet_tx_bd_struct_t *curBuffDescrip; + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId]; + enet_frame_info_t *txDirty = NULL; + uint32_t len = 0; + uint32_t sizeleft = 0; + uint32_t address; + status_t result = kStatus_Success; + uint32_t src; + uint32_t configVal; + bool isReturn = false; + uint32_t primask; + + /* Check the frame length. */ + if (length > ENET_FRAME_TX_LEN_LIMITATION(base)) + { + result = kStatus_ENET_TxFrameOverLen; + } + else + { + /* Check if the transmit buffer is ready. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + result = kStatus_ENET_TxFrameBusy; + } + /* Check txDirtyRing if need frameinfo in tx interrupt callback. */ + else if ((handle->txReclaimEnable[ringId]) && !ENET_TxDirtyRingAvailable(txDirtyRing)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + /* One transmit buffer is enough for one frame. */ + if (handle->txBuffSizeAlign[ringId] >= length) + { + /* Copy data to the buffer for uDMA transfer. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + (void)memcpy((void *)(uint32_t *)address, (const void *)(uint32_t *)(uint32_t)data, length); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + DCACHE_CleanByRange(address, length); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + /* Set data length. */ + curBuffDescrip->length = (uint16_t)length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } + +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Increase the buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + + /* Add context to frame info ring */ + if (handle->txReclaimEnable[ringId]) + { + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSendRing(base, ringId); + } + else + { + /* One frame requires more than one transmit buffers. */ + do + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Update the size left to be transmit. */ + sizeleft = length - len; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + src = (uint32_t)data + len; + + /* Increase the current software index of BD */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + + if (sizeleft > handle->txBuffSizeAlign[ringId]) + { + /* Data copy. */ + (void)memcpy((void *)(uint32_t *)address, (void *)(uint32_t *)src, + handle->txBuffSizeAlign[ringId]); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, handle->txBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + /* Data length update. */ + curBuffDescrip->length = handle->txBuffSizeAlign[ringId]; + len += handle->txBuffSizeAlign[ringId]; + /* Sets the control flag. */ + configVal = (uint32_t)curBuffDescrip->control; + configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + curBuffDescrip->control = (uint16_t)configVal; + + if (handle->txReclaimEnable[ringId]) + { + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + + /* Active the transmit buffer descriptor*/ + ENET_ActiveSendRing(base, ringId); + } + else + { + (void)memcpy((void *)(uint32_t *)address, (void *)(uint32_t *)src, sizeleft); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, sizeleft); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + curBuffDescrip->length = (uint16_t)sizeleft; + /* Set Last buffer wrap flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + + if (handle->txReclaimEnable[ringId]) + { + /* Add context to frame info ring */ + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSendRing(base, ringId); + isReturn = true; + break; + } + /* Update the buffer descriptor address. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)); + + if (isReturn == false) + { + result = kStatus_ENET_TxFrameBusy; + } + } + } + } + return result; +} + +/*! + * brief Enable or disable tx descriptors reclaim mechanism. + * note This function must be called when no pending send frame action. + * Set enable if you want to reclaim context or timestamp in interrupt. + * + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * param isEnable Enable or disable flag. + * param ringId The ring index or ring number. + * retval kStatus_Success Succeed to enable/disable Tx reclaim. + * retval kStatus_Fail Fail to enable/disable Tx reclaim. + */ +status_t ENET_SetTxReclaim(enet_handle_t *handle, bool isEnable, uint8_t ringId) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId]; + + status_t result = kStatus_Success; + + /* If tx dirty ring is empty, can set this flag and reset txConsumIdx */ + if ((txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) && ENET_TxDirtyRingAvailable(txDirtyRing)) + { + if (isEnable) + { + handle->txReclaimEnable[ringId] = true; + txBdRing->txConsumIdx = txBdRing->txGenIdx; + } + else + { + handle->txReclaimEnable[ringId] = false; + } + } + else + { + result = kStatus_Fail; + } + return result; +} + +/*! + * brief Reclaim tx descriptors. + * This function is used to update the tx descriptor status and + * store the tx timestamp when the 1588 feature is enabled. + * This is called by the transmit interupt IRQ handler after the + * complete of a frame transmission. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * param ringId The ring index or ring number. + */ +void ENET_ReclaimTxDescriptor(ENET_Type *base, enet_handle_t *handle, uint8_t ringId) +{ + assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base)); + + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + volatile enet_tx_bd_struct_t *curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx; + enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId]; + enet_frame_info_t *txDirty = NULL; + uint32_t primask; + + /* Need to update the first index for transmit buffer free. */ + while ((0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) && (txBdRing->txDescUsed > 0U)) + { + if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK) != 0U) + { + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txConsumIdx; + txDirtyRing->txConsumIdx = ENET_IncreaseIndex(txDirtyRing->txConsumIdx, txDirtyRing->txRingLen); + txDirtyRing->isFull = false; + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + txDirty->isTsAvail = false; + if ((curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK) != 0U) + { + enet_ptp_time_t *ts = &txDirty->timeStamp; + /* Get transmit time stamp second. */ + txDirty->isTsAvail = true; + ts->second = handle->msTimerSecond; + ts->nanosecond = curBuffDescrip->timestamp; + } +#endif + /* For tx buffer free or requeue for last descriptor. + * The tx interrupt callback should free/requeue the tx buffer. */ + if (handle->callback != NULL) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, ringId, kENET_TxEvent, txDirty, handle->userData); +#else + handle->callback(base, handle, kENET_TxEvent, txDirty, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed--; + EnableGlobalIRQ(primask); + + /* Update the index. */ + txBdRing->txConsumIdx = ENET_IncreaseIndex(txBdRing->txConsumIdx, txBdRing->txRingLen); + curBuffDescrip = txBdRing->txBdBase + txBdRing->txConsumIdx; + } +} + +/*! + * deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame. + */ +status_t ENET_GetRxBuffer(ENET_Type *base, + enet_handle_t *handle, + void **buffer, + uint32_t *length, + uint8_t ringId, + bool *isLastBuff, + uint32_t *ts) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + assert(handle->rxBdRing[ringId].rxBdBase != NULL); + assert(handle->rxBuffAlloc == NULL); + + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + uint32_t address; + + /* Check if current rx BD is under usage by certain application */ + /* Buffer owner flag, 1: owned by application, 0: owned by driver */ + if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK) == 0U) + { + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK; + } + else + { + return kStatus_ENET_RxFrameFail; + } + +/* A frame on one buffer or several receive buffers are both considered. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + *buffer = (void *)(uint32_t *)address; + *length = curBuffDescrip->length; + + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + /* This is a valid frame. */ + *isLastBuff = true; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (ts != NULL) + { + *ts = curBuffDescrip->timestamp; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + } + else + { + *isLastBuff = false; + } + + /* Increase current buffer descriptor to the next one. */ + rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + + return kStatus_Success; +} + +/*! + * deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame. + */ +void ENET_ReleaseRxBuffer(ENET_Type *base, enet_handle_t *handle, void *buffer, uint8_t ringId) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + enet_rx_bd_struct_t *ownBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase; + enet_rx_bd_struct_t *blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + enet_rx_bd_struct_t tempBuffDescrip; + uint16_t index = rxBdRing->rxGenIdx; + bool isReleaseBd = false; + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffer = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)buffer, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + + do + { + /* Find the BD for releasing, do nothing if it's not owned by application. */ + if (buffer == ownBuffDescrip->buffer) + { + if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK)) + { + isReleaseBd = true; + break; + } + } + + if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + break; + } + ownBuffDescrip++; + } while (true); + + if (isReleaseBd) + { + /* Find the first BD owned by application after rxBdCurrent, isReleaseBd is true so there's at least one BD is + * owned by application */ + do + { + if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK)) + { + break; + } + if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + blockBuffDescrip = (enet_rx_bd_struct_t *)(uint32_t)rxBdRing->rxBdBase; + } + else + { + blockBuffDescrip++; + } + index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen); + } while (index != rxBdRing->rxGenIdx); + + /* If the BD ready for releasing isn't the first BD owned by application after rxBdCurrent then exchange the two + * BDs */ + if (blockBuffDescrip != ownBuffDescrip) + { + /* Exchange buffer descriptor content */ + tempBuffDescrip = *ownBuffDescrip; + *ownBuffDescrip = *blockBuffDescrip; + *blockBuffDescrip = tempBuffDescrip; + + /* Maintain the wrap flag */ + if (0U != (ownBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + ownBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK); + blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + else if (0U != (blockBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK)) + { + blockBuffDescrip->control &= (uint16_t)(~ENET_BUFFDESCRIPTOR_RX_WRAP_MASK); + ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + else + { + /* Intentional empty */ + } + + /* Clears status including the owner flag. */ + blockBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + blockBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + } + else + { + /* Clears status including the owner flag. */ + ownBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + ownBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + } + + ENET_ActiveReadRing(base, ringId); + } +} + +static inline status_t ENET_GetRxFrameErr(enet_rx_bd_struct_t *rxDesc, enet_rx_frame_error_t *rxFrameError) +{ + assert(rxDesc != NULL); + assert(rxFrameError != NULL); + + status_t result = kStatus_Success; + uint16_t control = rxDesc->control; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint16_t controlExtend1 = rxDesc->controlExtend1; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + union _frame_error + { + uint32_t data; + enet_rx_frame_error_t frameError; + }; + union _frame_error error; + + (void)memset((void *)&error.frameError, 0, sizeof(enet_rx_frame_error_t)); + + /* The last buffer descriptor in the frame check the status of the received frame. */ + if (0U != (control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK)) + { + result = kStatus_ENET_RxFrameError; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (0U != (controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK)) + { + result = kStatus_ENET_RxFrameError; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + if (result != kStatus_Success) + { + error.data = control; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + error.data |= ((uint32_t)controlExtend1 << 16U); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + } + + *rxFrameError = error.frameError; + + return result; +} + +/*! + * brief Receives one frame in specified BD ring with zero copy. + * + * This function will use the user-defined allocate and free callback. Every time application gets one frame through + * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application. + * note This function will drop current frame and update related BDs as available for DMA if new buffers allocating + * fails. Application must provide a memory pool including at least BD number + 1 buffers to make this function work + * normally. If user calls this function in Rx interrupt handler, be careful that this function makes Rx BD ready with + * allocating new buffer(normal) or updating current BD(out of memory). If there's always new Rx frame input, Rx + * interrupt will be triggered forever. Application need to disable Rx interrupt according to specific design in this + * case. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * param rxFrame The received frame information structure provided by user. + * param ringId The ring index or ring number. + * retval kStatus_Success Succeed to get one frame and allocate new memory for Rx buffer. + * retval kStatus_ENET_RxFrameEmpty There's no Rx frame in the BD. + * retval kStatus_ENET_RxFrameError There's issue in this receiving. + * retval kStatus_ENET_RxFrameDrop There's no new buffer memory for BD, drop this frame. + */ +status_t ENET_GetRxFrame(ENET_Type *base, enet_handle_t *handle, enet_rx_frame_struct_t *rxFrame, uint8_t ringId) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + assert(handle->rxBdRing[ringId].rxBdBase != NULL); + assert(rxFrame != NULL); + assert(rxFrame->rxBuffArray != NULL); + + status_t result = kStatus_Success; + enet_rx_bd_ring_t *rxBdRing = &handle->rxBdRing[ringId]; + volatile enet_rx_bd_struct_t *curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + void *newBuff = NULL; + bool isLastBuff = false; + uint16_t buffLen = 0; + enet_buffer_struct_t *rxBuffer; + uint16_t index; + uint32_t address; + void *buffer; + + /* Check the current buffer descriptor's empty flag. If empty means there is no frame received. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK)) + { + result = kStatus_ENET_RxFrameEmpty; + } + else + { + index = rxBdRing->rxGenIdx; + do + { + /* Find the last buffer descriptor. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + /* The last buffer descriptor stores the status of rhis received frame. */ + result = ENET_GetRxFrameErr((enet_rx_bd_struct_t *)(uint32_t)curBuffDescrip, &rxFrame->rxFrameError); + break; + } + + /* Can't find the last BD flag, no valid frame. */ + index = ENET_IncreaseIndex(index, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + index; + if (index == rxBdRing->rxGenIdx) + { + result = kStatus_ENET_RxFrameEmpty; + break; + } + } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK)); + } + + /* Drop the error frame. */ + if (result == kStatus_ENET_RxFrameError) + { + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + do + { + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + isLastBuff = true; + } + + /* Clears status including the owner flag. */ + curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increase current buffer descriptor to the next one. */ + rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } while (!isLastBuff); + + ENET_ActiveReadRing(base, ringId); + + return result; + } + else if (result != kStatus_Success) + { + return result; + } + else + { + /* Intentional empty */ + } + + /* Get the valid frame */ + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + index = 0; + do + { + newBuff = handle->rxBuffAlloc(base, handle->userData, ringId); + if (newBuff != NULL) + { + rxBuffer = &rxFrame->rxBuffArray[index]; + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + address = MEMORY_ConvertMemoryMapAddress((uint32_t)curBuffDescrip->buffer, kMEMORY_DMA2Local); +#else + address = (uint32_t)curBuffDescrip->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + rxBuffer->buffer = (void *)(uint32_t *)address; + + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + /* This is a valid frame. */ + isLastBuff = true; + rxFrame->totLen = curBuffDescrip->length; + rxBuffer->length = curBuffDescrip->length - buffLen; + + rxFrame->rxAttribute.promiscuous = false; + if (0U != (base->RCR & ENET_RCR_PROM_MASK)) + { + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_MISS_MASK)) + { + rxFrame->rxAttribute.promiscuous = true; + } + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + rxFrame->rxAttribute.timestamp = curBuffDescrip->timestamp; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + } + else + { + rxBuffer->length = curBuffDescrip->length; + buffLen += rxBuffer->length; + } + + /* Give new buffer from application to BD */ + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffer = + (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)newBuff, kMEMORY_Local2DMA); +#else + buffer = newBuff; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->rxMaintainEnable[ringId]) + { + DCACHE_InvalidateByRange((uint32_t)(uint32_t *)buffer, handle->rxBuffSizeAlign[ringId]); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + curBuffDescrip->buffer = buffer; + + /* Clears status including the owner flag. */ + curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increase Rx array index and the buffer descriptor address. */ + index++; + rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } + else + { + /* Drop frame if there's no new buffer memory */ + + /* Free the incomplete frame buffers. */ + while (index-- != 0U) + { + handle->rxBuffFree(base, &rxFrame->rxBuffArray[index].buffer, handle->userData, ringId); + } + + /* Update left buffers as ready for next coming frame */ + do + { + /* The last buffer descriptor of a frame. */ + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK)) + { + isLastBuff = true; + } + + /* Clears status including the owner flag. */ + curBuffDescrip->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increase current buffer descriptor to the next one. */ + rxBdRing->rxGenIdx = ENET_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + curBuffDescrip = rxBdRing->rxBdBase + rxBdRing->rxGenIdx; + } while (!isLastBuff); + + result = kStatus_ENET_RxFrameDrop; + break; + } + } while (!isLastBuff); + + ENET_ActiveReadRing(base, ringId); + + return result; +} + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +static inline void ENET_PrepareTxDesc(volatile enet_tx_bd_struct_t *txDesc, enet_tx_config_struct_t *txConfig) +{ + uint16_t controlExtend1 = 0U; + + /* For enable the timestamp. */ + if (txConfig->intEnable) + { + controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK; + } + if (txConfig->tsEnable) + { + controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + if (txConfig->autoProtocolChecksum) + { + controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_PROTOCHECKSUM_MASK; + } + if (txConfig->autoIPChecksum) + { + controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_IPCHECKSUM_MASK; + } +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (txConfig->tltEnable) + { + controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_USETXLAUNCHTIME_MASK; + txDesc->txLaunchTimeLow |= txConfig->tltLow; + txDesc->txLaunchTimeHigh |= txConfig->tltHigh; + } + controlExtend1 |= (uint16_t)ENET_BD_FTYPE(txConfig->AVBFrameType); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + txDesc->controlExtend1 = controlExtend1; +} +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! + * brief Sends one frame in specified BD ring with zero copy. + * + * This function supports scattered buffer transmit, user needs to provide the buffer array. + * note Tx reclaim should be enabled to ensure the Tx buffer ownership can be given back to + * application after Tx is over. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * param txFrame The Tx frame structure. + * param ringId The ring index or ring number. + * retval kStatus_Success Succeed to send one frame. + * retval kStatus_ENET_TxFrameBusy The BD is not ready for Tx or the reclaim operation still not finishs. + * retval kStatus_ENET_TxFrameOverLen The Tx frame length is over max ethernet frame length. + */ +status_t ENET_StartTxFrame(ENET_Type *base, enet_handle_t *handle, enet_tx_frame_struct_t *txFrame, uint8_t ringId) +{ + assert(handle != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + assert(txFrame->txBuffArray != NULL); + assert(txFrame->txBuffNum != 0U); + assert(handle->txReclaimEnable[ringId]); + + volatile enet_tx_bd_struct_t *curBuffDescrip; + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId]; + status_t result = kStatus_Success; + enet_buffer_struct_t *txBuff = txFrame->txBuffArray; + uint32_t txBuffNum = txFrame->txBuffNum; + enet_frame_info_t *txDirty = NULL; + uint32_t frameLen = 0; + uint32_t idleDescNum = 0; + uint16_t index = 0; + uint32_t configVal; + uint32_t primask; + void *buffer; + + /* Calculate frame length and Tx data buffer number. */ + do + { + frameLen += txBuff->length; + txBuff++; + } while (--txBuffNum != 0U); + txBuffNum = txFrame->txBuffNum; + + /* Check whether the available BD number is enough for Tx data buffer. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + index = txBdRing->txGenIdx; + do + { + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + break; + } + + /* Idle BD number is enough */ + if (++idleDescNum >= txBuffNum) + { + break; + } + index = ENET_IncreaseIndex(index, txBdRing->txRingLen); + curBuffDescrip = txBdRing->txBdBase + index; + } while (index != txBdRing->txGenIdx); + + /* Check the frame length. */ + if (frameLen > ENET_FRAME_TX_LEN_LIMITATION(base)) + { + result = kStatus_ENET_TxFrameOverLen; + } + /* Return busy if idle BD is not enough. */ + else if (txBuffNum > idleDescNum) + { + result = kStatus_ENET_TxFrameBusy; + } + /* Check txDirtyRing if need frameinfo in tx interrupt callback. */ + else if (!ENET_TxDirtyRingAvailable(txDirtyRing)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + txBuff = txFrame->txBuffArray; + do + { + assert(txBuff->buffer != NULL); + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + if (handle->txMaintainEnable[ringId]) + { + DCACHE_CleanByRange((uint32_t)(uint32_t *)txBuff->buffer, txBuff->length); + } +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + /* Map loacl memory address to DMA for special platform. */ + buffer = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)txBuff->buffer, kMEMORY_Local2DMA); +#else + buffer = txBuff->buffer; +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + + /* Set data buffer and length. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + curBuffDescrip->buffer = (uint8_t *)(uint32_t *)buffer; + curBuffDescrip->length = txBuff->length; + + /* Increase txBuffer array address and the buffer descriptor address. */ + txBuff++; + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + ENET_PrepareTxDesc(curBuffDescrip, &txFrame->txConfig); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Linked buffers */ + if (--txBuffNum != 0U) + { + /* Set BD ready flag and clean last BD flag. */ + configVal = (uint32_t)curBuffDescrip->control; + configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + curBuffDescrip->control = (uint16_t)configVal; + + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + else + { + curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Add context to frame info ring */ + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = txFrame->context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + /* Active Tx BD everytime to speed up transfer */ + ENET_ActiveSendRing(base, ringId); + } while (txBuffNum != 0U); + } + return result; +} + +/*! + * deprecated Do not use this function. It has been superseded by @ref ENET_StartTxFrame. + */ +status_t ENET_SendFrameZeroCopy(ENET_Type *base, + enet_handle_t *handle, + const uint8_t *data, + uint32_t length, + uint8_t ringId, + bool tsFlag, + void *context) +{ + assert(handle != NULL); + assert(data != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + volatile enet_tx_bd_struct_t *curBuffDescrip; + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + enet_tx_dirty_ring_t *txDirtyRing = &handle->txDirtyRing[ringId]; + enet_frame_info_t *txDirty = NULL; + uint32_t len = 0; + uint32_t sizeleft = 0; + status_t result = kStatus_Success; + uint8_t *data_temp; + uint32_t configVal; + bool isReturn = false; + uint32_t primask; + + /* Check the frame length. */ + if (length > ENET_FRAME_TX_LEN_LIMITATION(base)) + { + result = kStatus_ENET_TxFrameOverLen; + } + else + { + /* Check if the transmit buffer is ready. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + if (0U != (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + result = kStatus_ENET_TxFrameBusy; + } + /* Check txDirtyRing if need frameinfo in tx interrupt callback. */ + else if (handle->txReclaimEnable[ringId] && !ENET_TxDirtyRingAvailable(txDirtyRing)) + { + result = kStatus_ENET_TxFrameBusy; + } + else + { + /* One transmit buffer is enough for one frame. */ + if (handle->txBuffSizeAlign[ringId] >= length) + { + /* Copy data to the buffer for uDMA transfer. */ +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + curBuffDescrip->buffer = (uint8_t *)(uint32_t)data; + /* Set data length. */ + curBuffDescrip->length = (uint16_t)length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } + +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + curBuffDescrip->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK); + + /* Increase the buffer descriptor address. */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + + /* Add context to frame info ring */ + if (handle->txReclaimEnable[ringId]) + { + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSendRing(base, ringId); + } + else + { + /* One frame requires more than one transmit buffers. */ + do + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (tsFlag) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= (uint16_t)(~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Update the size left to be transmit. */ + sizeleft = length - len; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + data = (uint8_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)data, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + data_temp = (uint8_t *)(uint32_t)data + len; + + /* Increase the current software index of BD */ + txBdRing->txGenIdx = ENET_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + + if (sizeleft > handle->txBuffSizeAlign[ringId]) + { + /* Set buffer. */ + curBuffDescrip->buffer = data_temp; + /* Data length update. */ + curBuffDescrip->length = handle->txBuffSizeAlign[ringId]; + len += handle->txBuffSizeAlign[ringId]; + /* Sets the control flag. */ + configVal = (uint32_t)curBuffDescrip->control; + configVal &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + configVal |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + curBuffDescrip->control = (uint16_t)configVal; + + if (handle->txReclaimEnable[ringId]) + { + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + + /* Active the transmit buffer descriptor*/ + ENET_ActiveSendRing(base, ringId); + } + else + { + curBuffDescrip->buffer = data_temp; + curBuffDescrip->length = (uint16_t)sizeleft; + /* Set Last buffer wrap flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + + if (handle->txReclaimEnable[ringId]) + { + /* Add context to frame info ring */ + txDirty = txDirtyRing->txDirtyBase + txDirtyRing->txGenIdx; + txDirty->context = context; + txDirtyRing->txGenIdx = ENET_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSendRing(base, ringId); + isReturn = true; + break; + } + /* Update buffer descriptor address. */ + curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + + } while (0U == (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)); + + if (isReturn == false) + { + result = kStatus_ENET_TxFrameBusy; + } + } + } + } + return result; +} + +/*! + * brief Adds the ENET device to a multicast group. + * + * param base ENET peripheral base address. + * param address The six-byte multicast group address which is provided by application. + */ +void ENET_AddMulticastGroup(ENET_Type *base, uint8_t *address) +{ + assert(address != NULL); + + enet_handle_t *handle = s_ENETHandle[ENET_GetInstance(base)]; + uint32_t crc = 0xFFFFFFFFU; + uint32_t count1 = 0; + uint32_t count2 = 0; + uint32_t configVal = 0; + + /* Calculates the CRC-32 polynomial on the multicast group address. */ + for (count1 = 0; count1 < ENET_FRAME_MACLEN; count1++) + { + uint8_t c = address[count1]; + for (count2 = 0; count2 < 0x08U; count2++) + { + if (0U != ((c ^ crc) & 1U)) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xEDB88320U; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + crc = crc >> 26U; + + handle->multicastCount[crc]++; + + /* Enable a multicast group address. */ + configVal = ((uint32_t)1U << (crc & 0x1FU)); + + if (0U != (crc & 0x20U)) + { + base->GAUR |= configVal; + } + else + { + base->GALR |= configVal; + } +} + +/*! + * brief Moves the ENET device from a multicast group. + * + * param base ENET peripheral base address. + * param address The six-byte multicast group address which is provided by application. + */ +void ENET_LeaveMulticastGroup(ENET_Type *base, uint8_t *address) +{ + assert(address != NULL); + + enet_handle_t *handle = s_ENETHandle[ENET_GetInstance(base)]; + uint32_t crc = 0xFFFFFFFFU; + uint32_t count1 = 0; + uint32_t count2 = 0; + uint32_t configVal = 0; + + /* Calculates the CRC-32 polynomial on the multicast group address. */ + for (count1 = 0; count1 < ENET_FRAME_MACLEN; count1++) + { + uint8_t c = address[count1]; + for (count2 = 0; count2 < 0x08U; count2++) + { + if (0U != ((c ^ crc) & 1U)) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xEDB88320U; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + crc = crc >> 26U; + + handle->multicastCount[crc]--; + + /* Set the hash table if no collisions */ + if (0U == handle->multicastCount[crc]) + { + configVal = ~((uint32_t)1U << (crc & 0x1FU)); + + if (0U != (crc & 0x20U)) + { + base->GAUR &= configVal; + } + else + { + base->GALR &= configVal; + } + } +} + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * brief Gets the ENET transmit frame statistics after the data send for specified ring. + * + * This interface gets the error statistics of the transmit frame. + * Because the error information is reported by the uDMA after the data delivery, this interface + * should be called after the data transmit API. It is recommended to call this function on + * transmit interrupt handler. After calling the ENET_SendFrame, the + * transmit interrupt notifies the transmit completion. + * + * param handle The PTP handler pointer. This is the same handler pointer used in the ENET_Init. + * param eErrorStatic The error statistics structure pointer. + * param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + * return The execute status. + */ +status_t ENET_GetTxErrAfterSendFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId) +{ + assert(handle != NULL); + assert(eErrorStatic != NULL); + assert(ringId < (uint8_t)FSL_FEATURE_ENET_QUEUE); + + uint16_t control = 0; + uint16_t controlExt = 0; + status_t result = kStatus_Success; + bool isReturn = false; + enet_tx_bd_ring_t *txBdRing = &handle->txBdRing[ringId]; + volatile enet_tx_bd_struct_t *curBuffDescrip = txBdRing->txBdBase + txBdRing->txGenIdx; + + do + { + /* Get the current dirty transmit buffer descriptor. */ + control = handle->txBdDirtyStatic[ringId]->control; + controlExt = handle->txBdDirtyStatic[ringId]->controlExtend0; + + /* Get the control status data, If the buffer descriptor has not been processed break out. */ + if (0U != (control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)) + { + result = kStatus_ENET_TxFrameBusy; + isReturn = true; + break; + } + + /* Increase the transmit dirty static pointer. */ + if (0U != (handle->txBdDirtyStatic[ringId]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK)) + { + handle->txBdDirtyStatic[ringId] = txBdRing->txBdBase; + } + else + { + handle->txBdDirtyStatic[ringId]++; + } + + /* If the transmit buffer descriptor is ready and the last buffer descriptor, store packet statistic. */ + if (0U != (control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK)) + { + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_ERR_MASK)) + { + /* Transmit error. */ + eErrorStatic->statsTxErr++; + } + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK)) + { + /* Transmit excess collision error. */ + eErrorStatic->statsTxExcessCollisionErr++; + } + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK)) + { + /* Transmit late collision error. */ + eErrorStatic->statsTxLateCollisionErr++; + } + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK)) + { + /* Transmit under flow error. */ + eErrorStatic->statsTxUnderFlowErr++; + } + if (0U != (controlExt & ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK)) + { + /* Transmit over flow error. */ + eErrorStatic->statsTxOverFlowErr++; + } + isReturn = true; + break; + } + + } while (handle->txBdDirtyStatic[ringId] != curBuffDescrip); + + if (isReturn == false) + { + result = kStatus_ENET_TxFrameFail; + } + return result; +} + +void ENET_Ptp1588ConfigureHandler(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig) +{ + assert(handle != NULL); + assert(ptpConfig != NULL); + uint8_t count; + + uint32_t mask = (uint32_t)kENET_TxBufferInterrupt; +#if FSL_FEATURE_ENET_QUEUE > 1 + mask |= (uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxBuffer2Interrupt; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + for (count = 0; count < handle->ringNum; count++) + { + handle->txBdDirtyStatic[count] = handle->txBdRing[count].txBdBase; + } + + /* Setting the receive and transmit state for transaction. */ + handle->msTimerSecond = 0; + +#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID + uint32_t refClock; + + /* The minimum time is defined by the greater of either six register clock cycles or six ptp clock cycles. */ + if (handle->enetClock <= ptpConfig->ptp1588ClockSrc_Hz) + { + /* Caculate how many core cycles delay is needed. */ + /* In the cases with this IP design issue, core clock = enetClock */ + handle->tsDelayCount = 6U * handle->enetClock; + } + else + { + refClock = ptpConfig->ptp1588ClockSrc_Hz; + + /* Caculate how many core cycles delay is needed. */ + /* In the cases with this IP design issue, core clock = enetClock */ + handle->tsDelayCount = 6U * ((handle->enetClock + refClock - 1U) / refClock); + } + +#endif + + ENET_DisableInterrupts(base, mask); + + /* Set the IRQ handler when the interrupt is enabled. */ + ENET_SetTsISRHandler(base, ENET_TimeStampIRQHandler); + ENET_SetTxISRHandler(base, ENET_TransmitIRQHandler); + + /* Enables the time stamp interrupt and transmit frame interrupt to + * handle the time-stamp . */ + ENET_EnableInterrupts(base, (ENET_TS_INTERRUPT | ENET_TX_INTERRUPT)); +} + +/*! + * brief Configures the ENET PTP IEEE 1588 feature with the basic configuration. + * The function sets the clock for PTP 1588 timer and enables + * time stamp interrupts and transmit interrupts for PTP 1588 features. + * This API should be called when the 1588 feature is enabled + * or the ENET_ENHANCEDBUFFERDESCRIPTOR_MODE is defined. + * ENET_Init should be called before calling this API. + * + * note The PTP 1588 time-stamp second increase though time-stamp interrupt handler + * and the transmit time-stamp store is done through transmit interrupt handler. + * As a result, the TS interrupt and TX interrupt are enabled when you call this API. + * + * param base ENET peripheral base address. + * param handle ENET handler pointer. + * param ptpConfig The ENET PTP1588 configuration. + */ +void ENET_Ptp1588Configure(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig) +{ + assert(handle != NULL); + assert(ptpConfig != NULL); + + /* Start the 1588 timer. */ + ENET_Ptp1588StartTimer(base, ptpConfig->ptp1588ClockSrc_Hz); + + ENET_Ptp1588ConfigureHandler(base, handle, ptpConfig); +} + +/*! + * brief Starts the ENET PTP 1588 Timer. + * This function is used to initialize the PTP timer. After the PTP starts, + * the PTP timer starts running. + * + * param base ENET peripheral base address. + * param ptpClkSrc The clock source of the PTP timer. + */ +void ENET_Ptp1588StartTimer(ENET_Type *base, uint32_t ptpClkSrc) +{ + /* Restart PTP 1588 timer, master clock. */ + base->ATCR = ENET_ATCR_RESTART_MASK; + + /* Initializes PTP 1588 timer. */ + base->ATINC = ENET_ATINC_INC(ENET_NANOSECOND_ONE_SECOND / ptpClkSrc); + base->ATPER = ENET_NANOSECOND_ONE_SECOND; + /* Sets periodical event and the event signal output assertion and Actives PTP 1588 timer. */ + base->ATCR = ENET_ATCR_PEREN_MASK | ENET_ATCR_PINPER_MASK | ENET_ATCR_EN_MASK; +} + +/*! + * brief Gets the current ENET time from the PTP 1588 timer. + * Interrupts are not disabled. + * + * param base ENET peripheral base address. + * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + * param ptpTime The PTP timer structure. + */ +void ENET_Ptp1588GetTimerNoIrqDisable(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime) +{ + /* Get the current PTP time. */ + ptpTime->second = handle->msTimerSecond; + /* Get the nanosecond from the master timer. */ + base->ATCR |= ENET_ATCR_CAPTURE_MASK; + +#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID + /* The whole while loop includes at least three instructions(subs, nop and bne). */ + uint32_t count = (handle->tsDelayCount + 3U - 1U) / 3U; + + while (0U != (count--)) + { + __NOP(); + } +#else + /* Wait for capture over */ + while (0U != (base->ATCR & ENET_ATCR_CAPTURE_MASK)) + { + } +#endif + + /* Get the captured time. */ + ptpTime->nanosecond = base->ATVR; +} + +/*! + * brief Gets the current ENET time from the PTP 1588 timer. + * + * param base ENET peripheral base address. + * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + * param ptpTime The PTP timer structure. + */ +void ENET_Ptp1588GetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime) +{ + assert(handle != NULL); + assert(ptpTime != NULL); + uint32_t primask; + + /* Disables the interrupt. */ + primask = DisableGlobalIRQ(); + + ENET_Ptp1588GetTimerNoIrqDisable(base, handle, ptpTime); + + /* Get PTP timer wrap event. */ + if (0U != (base->EIR & (uint32_t)kENET_TsTimerInterrupt)) + { + ptpTime->second++; + } + + /* Enables the interrupt. */ + EnableGlobalIRQ(primask); +} + +/*! + * brief Sets the ENET PTP 1588 timer to the assigned time. + * + * param base ENET peripheral base address. + * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + * param ptpTime The timer to be set to the PTP timer. + */ +void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime) +{ + assert(handle != NULL); + assert(ptpTime != NULL); + + uint32_t primask; + + /* Disables the interrupt. */ + primask = DisableGlobalIRQ(); + + /* Sets PTP timer. */ + handle->msTimerSecond = ptpTime->second; + base->ATVR = ptpTime->nanosecond; + + /* Enables the interrupt. */ + EnableGlobalIRQ(primask); +} + +/*! + * brief Adjusts the ENET PTP 1588 timer. + * + * param base ENET peripheral base address. + * param corrIncrease The correction increment value. This value is added every time the correction + * timer expires. A value less than the PTP timer frequency(1/ptpClkSrc) slows down the timer, + * a value greater than the 1/ptpClkSrc speeds up the timer. + * param corrPeriod The PTP timer correction counter wrap-around value. This defines after how + * many timer clock the correction counter should be reset and trigger a correction + * increment on the timer. A value of 0 disables the correction counter and no correction occurs. + */ +void ENET_Ptp1588AdjustTimer(ENET_Type *base, uint32_t corrIncrease, uint32_t corrPeriod) +{ + /* Set correction for PTP timer increment. */ + base->ATINC = (base->ATINC & ~ENET_ATINC_INC_CORR_MASK) | (corrIncrease << ENET_ATINC_INC_CORR_SHIFT); + /* Set correction for PTP timer period. */ + base->ATCOR = (base->ATCOR & ~ENET_ATCOR_COR_MASK) | (corrPeriod << ENET_ATCOR_COR_SHIFT); +} + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB +/*! + * brief Sets the ENET AVB feature. + * + * ENET AVB feature configuration, set the Receive classification match and transmit + * bandwidth. This API is called when the AVB feature is required. + * + * Note: The AVB frames transmission scheme is credit-based tx scheme and it's only supported + * with the Enhanced buffer descriptors. so the AVB configuration should only done with + * Enhanced buffer descriptor. so when the AVB feature is required, please make sure the + * the "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" is defined. + * + * param base ENET peripheral base address. + * param handle ENET handler pointer. + * param config The ENET AVB feature configuration structure. + */ +void ENET_AVBConfigure(ENET_Type *base, enet_handle_t *handle, const enet_avb_config_t *config) +{ + assert(config != NULL); + assert(FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) != -1); + + uint8_t count = 0; + + for (count = 0; count < (uint8_t)FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) - 1U; count++) + { + /* Set the AVB receive ring classification match when the match is not 0. */ + if (0U != (config->rxClassifyMatch[count])) + { + base->RCMR[count] = ((uint32_t)config->rxClassifyMatch[count] & 0xFFFFU) | ENET_RCMR_MATCHEN_MASK; + } + /* Set the dma controller for the extended ring. */ + base->DMACFG[count] |= ENET_DMACFG_IDLE_SLOPE(config->idleSlope[count]); + } + + /* Shall use the credit-based scheme for avb. */ + base->QOS &= ~ENET_QOS_TX_SCHEME_MASK; + base->QOS |= ENET_QOS_RX_FLUSH0_MASK; +} +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief The transmit IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId) +#else +/*! + * brief The transmit IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle) +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +{ + assert(handle != NULL); + uint32_t mask = (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt; + uint32_t index = 0; + uint32_t irq; + +/* Check if the transmit interrupt happen. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + switch (ringId) + { + case kENET_Ring1: + mask = ((uint32_t)kENET_TxFrame1Interrupt | (uint32_t)kENET_TxBuffer1Interrupt); + break; + case kENET_Ring2: + mask = ((uint32_t)kENET_TxFrame2Interrupt | (uint32_t)kENET_TxBuffer2Interrupt); + break; + default: + mask = (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt; + break; + } + index = ringId; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + while (0U != (mask & base->EIR)) + { + irq = base->EIR; + + /* Clear the transmit interrupt event. */ + base->EIR = mask; + + /* Callback Handler. */ + if (handle->txReclaimEnable[index] && (0U != (irq & (uint32_t)kENET_TxFrameInterrupt))) + { + ENET_ReclaimTxDescriptor(base, handle, (uint8_t)index); + } + else + { + if (NULL != handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, index, kENET_TxEvent, NULL, handle->userData); +#else + handle->callback(base, handle, kENET_TxEvent, NULL, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + } +} + +/*! + * brief The receive IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +#if FSL_FEATURE_ENET_QUEUE > 1 +void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId) +#else +void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle) +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +{ + assert(handle != NULL); + uint32_t mask = (uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt; + +/* Check if the receive interrupt happen. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + switch (ringId) + { + case kENET_Ring1: + mask = ((uint32_t)kENET_RxFrame1Interrupt | (uint32_t)kENET_RxBuffer1Interrupt); + break; + case kENET_Ring2: + mask = ((uint32_t)kENET_RxFrame2Interrupt | (uint32_t)kENET_RxBuffer2Interrupt); + break; + default: + mask = (uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt; + break; + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + while (0U != (mask & base->EIR)) + { + /* Clear the transmit interrupt event. */ + base->EIR = mask; + + /* Callback function. */ + if (NULL != handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, ringId, kENET_RxEvent, NULL, handle->userData); +#else + handle->callback(base, handle, kENET_RxEvent, NULL, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } +} + +/*! + * brief Some special IRQ handler including the error, mii, wakeup irq handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_ErrorIRQHandler(ENET_Type *base, enet_handle_t *handle) +{ + assert(handle != NULL); + + uint32_t errMask = (uint32_t)kENET_BabrInterrupt | (uint32_t)kENET_BabtInterrupt | (uint32_t)kENET_EBusERInterrupt | + (uint32_t)kENET_PayloadRxInterrupt | (uint32_t)kENET_LateCollisionInterrupt | + (uint32_t)kENET_RetryLimitInterrupt | (uint32_t)kENET_UnderrunInterrupt; + + /* Check if the error interrupt happen. */ + if (0U != ((uint32_t)kENET_WakeupInterrupt & base->EIR)) + { + /* Clear the wakeup interrupt. */ + base->EIR = (uint32_t)kENET_WakeupInterrupt; + /* wake up and enter the normal mode. */ + ENET_EnableSleepMode(base, false); + /* Callback function. */ + if (NULL != handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_WakeUpEvent, NULL, handle->userData); +#else + handle->callback(base, handle, kENET_WakeUpEvent, NULL, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + else + { + /* Clear the error interrupt event status. */ + errMask &= base->EIR; + base->EIR = errMask; + /* Callback function. */ + if (NULL != handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_ErrEvent, NULL, handle->userData); +#else + handle->callback(base, handle, kENET_ErrEvent, NULL, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } +} + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * brief The IEEE 1588 PTP time stamp interrupt handler. + * + * param base ENET peripheral base address. + * param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + */ +void ENET_TimeStampIRQHandler(ENET_Type *base, enet_handle_t *handle) +{ + assert(handle != NULL); + + /* Check if the PTP time stamp interrupt happen. */ + if (0U != ((uint32_t)kENET_TsTimerInterrupt & base->EIR)) + { + /* Clear the time stamp interrupt. */ + base->EIR = (uint32_t)kENET_TsTimerInterrupt; + + /* Increase timer second counter. */ + handle->msTimerSecond++; + + /* Callback function. */ + if (NULL != handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_TimeStampEvent, NULL, handle->userData); +#else + handle->callback(base, handle, kENET_TimeStampEvent, NULL, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + + if (0U != ((uint32_t)kENET_TsAvailInterrupt & base->EIR)) + { + /* Clear the time stamp interrupt. */ + base->EIR = (uint32_t)kENET_TsAvailInterrupt; + /* Callback function. */ + if (NULL != handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_TimeStampAvailEvent, NULL, handle->userData); +#else + handle->callback(base, handle, kENET_TimeStampAvailEvent, NULL, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } +} +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! + * brief the common IRQ handler for the tx/rx/error etc irq handler. + * + * This is used for the combined tx/rx/error interrupt for single/mutli-ring (frame 0). + * + * param base ENET peripheral base address. + */ +void ENET_CommonFrame0IRQHandler(ENET_Type *base) +{ + uint32_t event = base->EIR; + uint32_t instance = ENET_GetInstance(base); + + event &= base->EIMR; + if (0U != (event & ((uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrameInterrupt))) + { + if (s_enetTxIsr[instance] != NULL) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + s_enetTxIsr[instance](base, s_ENETHandle[instance], 0); +#else + s_enetTxIsr[instance](base, s_ENETHandle[instance]); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + + if (0U != (event & ((uint32_t)kENET_RxBufferInterrupt | (uint32_t)kENET_RxFrameInterrupt))) + { + if (s_enetRxIsr[instance] != NULL) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + s_enetRxIsr[instance](base, s_ENETHandle[instance], 0); +#else + s_enetRxIsr[instance](base, s_ENETHandle[instance]); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + + if (0U != (event & ENET_TS_INTERRUPT) && (NULL != s_enetTsIsr[instance])) + { + s_enetTsIsr[instance](base, s_ENETHandle[instance]); + } + if (0U != (event & ENET_ERR_INTERRUPT) && (NULL != s_enetErrIsr[instance])) + { + s_enetErrIsr[instance](base, s_ENETHandle[instance]); + } +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief the common IRQ handler for the tx/rx irq handler. + * + * This is used for the combined tx/rx interrupt for multi-ring (frame 1). + * + * param base ENET peripheral base address. + */ +void ENET_CommonFrame1IRQHandler(ENET_Type *base) +{ + uint32_t event = base->EIR; + uint32_t instance = ENET_GetInstance(base); + + event &= base->EIMR; + if (0U != (event & ((uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxFrame1Interrupt))) + { + if (s_enetTxIsr[instance] != NULL) + { + s_enetTxIsr[instance](base, s_ENETHandle[instance], 1); + } + } + + if (0U != (event & ((uint32_t)kENET_RxBuffer1Interrupt | (uint32_t)kENET_RxFrame1Interrupt))) + { + if (s_enetRxIsr[instance] != NULL) + { + s_enetRxIsr[instance](base, s_ENETHandle[instance], 1); + } + } +} + +/*! + * brief the common IRQ handler for the tx/rx irq handler. + * + * This is used for the combined tx/rx interrupt for multi-ring (frame 2). + * + * param base ENET peripheral base address. + */ +void ENET_CommonFrame2IRQHandler(ENET_Type *base) +{ + uint32_t event = base->EIR; + uint32_t instance = ENET_GetInstance(base); + + event &= base->EIMR; + if (0U != (event & ((uint32_t)kENET_TxBuffer2Interrupt | (uint32_t)kENET_TxFrame2Interrupt))) + { + if (s_enetTxIsr[instance] != NULL) + { + s_enetTxIsr[instance](base, s_ENETHandle[instance], 2); + } + } + + if (0U != (event & ((uint32_t)kENET_RxBuffer2Interrupt | (uint32_t)kENET_RxFrame2Interrupt))) + { + if (s_enetRxIsr[instance] != NULL) + { + s_enetRxIsr[instance](base, s_ENETHandle[instance], 2); + } + } +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +void ENET_Ptp1588IRQHandler(ENET_Type *base) +{ + uint32_t instance = ENET_GetInstance(base); + +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) && ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* In some platforms, the 1588 event uses same irq with timestamp event. */ + if ((s_enetTsIrqId[instance] == s_enet1588TimerIrqId[instance]) && (s_enetTsIrqId[instance] != NotAvail_IRQn)) + { + uint32_t event = base->EIR; + event &= base->EIMR; + if (0U != (event & ((uint32_t)kENET_TsTimerInterrupt | (uint32_t)kENET_TsAvailInterrupt))) + { + if (s_enetTsIsr[instance] != NULL) + { + s_enetTsIsr[instance](base, s_ENETHandle[instance]); + } + } + } +#endif + + if (s_enet1588TimerIsr[instance] != NULL) + { + s_enet1588TimerIsr[instance](base, s_ENETHandle[instance]); + } +} + +#if defined(ENET) +#if FSL_FEATURE_ENET_QUEUE < 2 +void ENET_TxIRQHandler(ENET_Type *base); +void ENET_TxIRQHandler(ENET_Type *base) +{ + uint32_t instance = ENET_GetInstance(base); + + if (s_enetTxIsr[instance] != NULL) + { + s_enetTxIsr[instance](base, s_ENETHandle[instance]); + } + SDK_ISR_EXIT_BARRIER; +} + +void ENET_RxIRQHandler(ENET_Type *base); +void ENET_RxIRQHandler(ENET_Type *base) +{ + uint32_t instance = ENET_GetInstance(base); + + if (s_enetRxIsr[instance] != NULL) + { + s_enetRxIsr[instance](base, s_ENETHandle[instance]); + } +} + +void ENET_ErrIRQHandler(ENET_Type *base); +void ENET_ErrIRQHandler(ENET_Type *base) +{ + uint32_t instance = ENET_GetInstance(base); + + if (s_enetErrIsr[instance] != NULL) + { + s_enetErrIsr[instance](base, s_ENETHandle[instance]); + } +} + +void ENET_Transmit_DriverIRQHandler(void); +void ENET_Transmit_DriverIRQHandler(void) +{ + ENET_TxIRQHandler(ENET); + SDK_ISR_EXIT_BARRIER; +} + +void ENET_Receive_DriverIRQHandler(void); +void ENET_Receive_DriverIRQHandler(void) +{ + ENET_RxIRQHandler(ENET); + SDK_ISR_EXIT_BARRIER; +} + +void ENET_Error_DriverIRQHandler(void); +void ENET_Error_DriverIRQHandler(void) +{ + ENET_ErrIRQHandler(ENET); + SDK_ISR_EXIT_BARRIER; +} +#endif /* FSL_FEATURE_ENET_QUEUE < 2 */ + +void ENET_DriverIRQHandler(int vector, void *param); +void ENET_DriverIRQHandler(int vector, void *param) +{ + ENET_CommonFrame0IRQHandler(ENET); + SDK_ISR_EXIT_BARRIER; +} +DECLARE_HW_IRQ(ENET_IRQn, ENET_DriverIRQHandler, NONE); + +void ENET_1588_Timer_DriverIRQHandler(void); +void ENET_1588_Timer_DriverIRQHandler(void) +{ + ENET_Ptp1588IRQHandler(ENET); + SDK_ISR_EXIT_BARRIER; +} +#endif /* ENET */ + +#if defined(ENET1) +void ENET1_DriverIRQHandler(void); +void ENET1_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET1); + SDK_ISR_EXIT_BARRIER; +} +#endif /* ENET1 */ + +#if defined(ENET2) +void ENET2_DriverIRQHandler(void); +void ENET2_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET2); + SDK_ISR_EXIT_BARRIER; +} + +void ENET2_1588_Timer_DriverIRQHandler(void); +void ENET2_1588_Timer_DriverIRQHandler(void) +{ + ENET_Ptp1588IRQHandler(ENET2); + SDK_ISR_EXIT_BARRIER; +} +#endif /* ENET2 */ + +#if defined(CONNECTIVITY__ENET0) +void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET0); + SDK_ISR_EXIT_BARRIER; +} +#if FSL_FEATURE_ENET_QUEUE > 1 +void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET0); + SDK_ISR_EXIT_BARRIER; +} +void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET0); + SDK_ISR_EXIT_BARRIER; +} +void CONNECTIVITY_ENET0_TIMER_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET0_TIMER_INT_DriverIRQHandler(void) +{ + ENET_Ptp1588IRQHandler(CONNECTIVITY__ENET0); + SDK_ISR_EXIT_BARRIER; +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +#endif /* CONNECTIVITY__ENET0 */ +#if defined(CONNECTIVITY__ENET1) +void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET1); + SDK_ISR_EXIT_BARRIER; +} +#if FSL_FEATURE_ENET_QUEUE > 1 +void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET1); + SDK_ISR_EXIT_BARRIER; +} +void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET1); + SDK_ISR_EXIT_BARRIER; +} +void CONNECTIVITY_ENET1_TIMER_INT_DriverIRQHandler(void); +void CONNECTIVITY_ENET1_TIMER_INT_DriverIRQHandler(void) +{ + ENET_Ptp1588IRQHandler(CONNECTIVITY__ENET1); + SDK_ISR_EXIT_BARRIER; +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +#endif /* CONNECTIVITY__ENET1 */ +#if FSL_FEATURE_ENET_QUEUE > 1 +#if defined(ENET_1G) +void ENET_1G_DriverIRQHandler(void); +void ENET_1G_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET_1G); + SDK_ISR_EXIT_BARRIER; +} +void ENET_1G_MAC0_Tx_Rx_1_DriverIRQHandler(void); +void ENET_1G_MAC0_Tx_Rx_1_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(ENET_1G); + SDK_ISR_EXIT_BARRIER; +} +void ENET_1G_MAC0_Tx_Rx_2_DriverIRQHandler(void); +void ENET_1G_MAC0_Tx_Rx_2_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(ENET_1G); + SDK_ISR_EXIT_BARRIER; +} +void ENET_1G_1588_Timer_DriverIRQHandler(void); +void ENET_1G_1588_Timer_DriverIRQHandler(void) +{ + ENET_Ptp1588IRQHandler(ENET_1G); + SDK_ISR_EXIT_BARRIER; +} +#endif /* ENET_1G */ + +#if defined(ENET1) +void ENET1_MAC0_Rx_Tx_Done0_DriverIRQHandler(void); +void ENET1_MAC0_Rx_Tx_Done0_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(ENET1); + SDK_ISR_EXIT_BARRIER; +} +void ENET1_MAC0_Rx_Tx_Done1_DriverIRQHandler(void); +void ENET1_MAC0_Rx_Tx_Done1_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(ENET1); + SDK_ISR_EXIT_BARRIER; +} +void ENET1_1588_Timer_DriverIRQHandler(void); +void ENET1_1588_Timer_DriverIRQHandler(void) +{ + ENET_Ptp1588IRQHandler(ENET1); + SDK_ISR_EXIT_BARRIER; +} +#endif /* ENET1 */ +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/fsl_enet_qos.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/fsl_enet_qos.c new file mode 100644 index 000000000..c3ab82ffd --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/fsl_enet_qos.c @@ -0,0 +1,3662 @@ +/* + * Copyright 2019-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_enet_qos.h" +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.enet_qos" +#endif + +/*! @brief Defines 10^9 nanosecond. */ +#define ENET_QOS_NANOSECS_ONESECOND (1000000000U) +/*! @brief Defines 10^6 microsecond.*/ +#define ENET_QOS_MICRSECS_ONESECOND (1000000U) + +/*! @brief Rx buffer LSB ignore bits. */ +#define ENET_QOS_RXBUFF_IGNORELSB_BITS (3U) +/*! @brief ENET FIFO size unit. */ +#define ENET_QOS_FIFOSIZE_UNIT (256U) +/*! @brief ENET half-dulpex default IPG. */ +#define ENET_QOS_HALFDUPLEX_DEFAULTIPG (4U) +/*! @breif ENET miminum ring length. */ +#define ENET_QOS_MIN_RINGLEN (4U) +/*! @breif ENET wakeup filter numbers. */ +#define ENET_QOS_WAKEUPFILTER_NUM (8U) +/*! @breif Requried systime timer frequency. */ +#define ENET_QOS_SYSTIME_REQUIRED_CLK_MHZ (50U) +/*! @brief Ethernet VLAN tag length. */ +#define ENET_QOS_FRAME_VLAN_TAGLEN 4U + +/*! @brief AVB TYPE */ +#define ENET_QOS_AVBTYPE 0x22F0U +#define ENET_QOS_HEAD_TYPE_OFFSET (12) +#define ENET_QOS_HEAD_AVBTYPE_OFFSET (16) + +/*! @brief Defines the macro for converting constants from host byte order to network byte order. */ +#define ENET_QOS_HTONS(n) __REV16(n) +#define ENET_QOS_HTONL(n) __REV(n) +#define ENET_QOS_NTOHS(n) __REV16(n) +#define ENET_QOS_NTOHL(n) __REV(n) + +#define ENET_QOS_DMA_CHX_RX_CTRL_RBSZ +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Increase the index in the ring. + * + * @param index The current index. + * @param max The size. + * @return the increased index. + */ +static uint16_t ENET_QOS_IncreaseIndex(uint16_t index, uint16_t max); + +/*! + * @brief Poll status flag. + * + * @param regAddr The register address to read out status + * @param mask The mask to operate the register value. + * @param readyStatus Indicate readyStatus for the field + * @retval kStatus_Success Poll readyStatus Success. + * @retval kStatus_ENET_QOS_Timeout Poll readyStatus timeout. + */ +static status_t ENET_QOS_PollStatusFlag(volatile uint32_t *regAddr, uint32_t mask, uint32_t readyStatus); + +/*! + * @brief Set ENET DMA controller with the configuration. + * + * @param base ENET peripheral base address. + * @param config ENET Mac configuration. + */ +static void ENET_QOS_SetDMAControl(ENET_QOS_Type *base, const enet_qos_config_t *config); + +/*! + * @brief Set ENET MAC controller with the configuration. + * + * @param base ENET peripheral base address. + * @param config ENET Mac configuration. + * @param macAddr ENET six-byte mac address. + */ +static void ENET_QOS_SetMacControl(ENET_QOS_Type *base, + const enet_qos_config_t *config, + uint8_t *macAddr, + uint8_t macCount); +/*! + * @brief Set ENET MTL with the configuration. + * + * @param base ENET peripheral base address. + * @param config ENET Mac configuration. + */ +static void ENET_QOS_SetMTL(ENET_QOS_Type *base, const enet_qos_config_t *config); + +/*! + * @brief Set ENET DMA transmit buffer descriptors for one channel. + * + * @param base ENET peripheral base address. + * @param bufferConfig ENET buffer configuration. + * @param intTxEnable tx interrupt enable. + * @param channel The channel number, 0 , 1. + */ +static status_t ENET_QOS_TxDescriptorsInit(ENET_QOS_Type *base, + const enet_qos_buffer_config_t *bufferConfig, + bool intTxEnable, + uint8_t channel); + +/*! + * @brief Set ENET DMA receive buffer descriptors for one channel. + * + * @param base ENET peripheral base address. + * @param bufferConfig ENET buffer configuration. + * @param intRxEnable tx interrupt enable. + * @param channel The channel number, 0, 1. + */ +static status_t ENET_QOS_RxDescriptorsInit(ENET_QOS_Type *base, + enet_qos_config_t *config, + const enet_qos_buffer_config_t *bufferConfig, + bool intRxEnable, + uint8_t channel); + +/*! + * @brief Sets the ENET 1588 feature. + * + * Enable the enhacement 1588 buffer descriptor mode and start + * the 1588 timer. + * + * @param base ENET peripheral base address. + * @param config The ENET configuration. + * @param refClk_Hz The reference clock for ptp 1588. + */ +static status_t ENET_QOS_SetPtp1588(ENET_QOS_Type *base, const enet_qos_config_t *config, uint32_t refClk_Hz); + +/*! + * @brief Store the receive time-stamp for event PTP frame in the time-stamp buffer ring. + * + * @param base ENET peripheral base address. + * @param handle ENET handler. + * @param rxDesc The ENET receive descriptor pointer. + * @param channel The rx channel. + * @param ts The timestamp structure pointer. + */ +static void ENET_QOS_StoreRxFrameTime(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + enet_qos_rx_bd_struct_t *rxDesc, + // uint8_t channel, + enet_qos_ptp_time_t *ts); + +/*! + * @brief Check if txDirtyRing available. + * + * @param txDirtyRing pointer to txDirtyRing + * @retval txDirty available status. + */ +static inline bool ENET_QOS_TxDirtyRingAvailable(enet_qos_tx_dirty_ring_t *txDirtyRing); + +/******************************************************************************* + * Variables + ******************************************************************************/ +/*! @brief Pointers to enet bases for each instance. */ +static ENET_QOS_Type *const s_enetqosBases[] = ENET_QOS_BASE_PTRS; + +/*! @brief Pointers to enet IRQ number for each instance. */ +static const IRQn_Type s_enetqosIrqId[] = ENET_QOS_IRQS; + +/* ENET ISR for transactional APIs. */ +static enet_qos_isr_t s_enetqosIsr; + +/*! @brief Pointers to enet handles for each instance. */ +static enet_qos_handle_t *s_ENETHandle[ARRAY_SIZE(s_enetqosBases)] = {NULL}; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to enet clocks for each instance. */ +const clock_ip_name_t s_enetqosClock[ARRAY_SIZE(s_enetqosBases)] = ENETQOS_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +static status_t ENET_QOS_PollStatusFlag(volatile uint32_t *regAddr, uint32_t mask, uint32_t readyStatus) +{ + uint8_t retryTimes = 10U; + status_t result = kStatus_Success; + + while ((readyStatus != (*regAddr & mask)) && (0U != retryTimes)) + { + retryTimes--; + SDK_DelayAtLeastUs(1U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); + } + + if (retryTimes == 0U) + { + result = kStatus_ENET_QOS_Timeout; + } + + return result; +} + +/*! + * brief Sets the ENET AVB feature. + * + * ENET_QOS AVB feature configuration, set transmit bandwidth. + * This API is called when the AVB feature is required. + * + * param base ENET_QOS peripheral base address. + * param config The ENET_QOS AVB feature configuration structure. + * param queueIndex ENET_QOS queue index. + */ +void ENET_QOS_AVBConfigure(ENET_QOS_Type *base, const enet_qos_cbs_config_t *config, uint8_t queueIndex) +{ + assert(config != NULL); + + /* Enable AV algorithm */ + base->MTL_QUEUE[queueIndex].MTL_TXQX_ETS_CTRL |= ENET_QOS_MTL_TXQX_ETS_CTRL_AVALG_MASK; + /* Configure send slope */ + base->MTL_QUEUE[queueIndex].MTL_TXQX_SNDSLP_CRDT = config->sendSlope; + /* Configure idle slope (same register as tx weight) */ + base->MTL_QUEUE[queueIndex].MTL_TXQX_QNTM_WGHT = config->idleSlope; + /* Configure high credit */ + base->MTL_QUEUE[queueIndex].MTL_TXQX_HI_CRDT = config->highCredit; + /* Configure high credit */ + base->MTL_QUEUE[queueIndex].MTL_TXQX_LO_CRDT = config->lowCredit; +} + +static uint16_t ENET_QOS_IncreaseIndex(uint16_t index, uint16_t max) +{ + /* Increase the index. */ + index++; + if (index >= max) + { + index = 0; + } + return index; +} + +static uint32_t ENET_QOS_ReverseBits(uint32_t value) +{ + value = ((value & 0x55555555UL) << 1U) | ((value >> 1U) & 0x55555555UL); + value = ((value & 0x33333333UL) << 2U) | ((value >> 2U) & 0x33333333UL); + value = ((value & 0x0F0F0F0FUL) << 4U) | ((value >> 4U) & 0x0F0F0F0FUL); + + return (value >> 24U) | ((value >> 8U) & 0xFF00UL) | ((value & 0xFF00UL) << 8U) | (value << 24U); +} + +static void ENET_QOS_SetDMAControl(ENET_QOS_Type *base, const enet_qos_config_t *config) +{ + assert(config != NULL); + + uint8_t index; + uint32_t reg; + uint32_t burstLen; + + /* Reset first and wait for the complete + * The reset bit will automatically be cleared after complete. */ + base->DMA_MODE |= ENET_QOS_DMA_MODE_SWR_MASK; + while ((base->DMA_MODE & ENET_QOS_DMA_MODE_SWR_MASK) != 0U) + { + } + + /* Set the burst length. */ + for (index = 0; index < ENET_QOS_RING_NUM_MAX; index++) + { + burstLen = (uint32_t)kENET_QOS_BurstLen1; + if (config->multiqueueCfg != NULL) + { + burstLen = (uint32_t)config->multiqueueCfg->burstLen; + } + base->DMA_CH[index].DMA_CHX_CTRL = burstLen & ENET_QOS_DMA_CHX_CTRL_PBLx8_MASK; + + reg = base->DMA_CH[index].DMA_CHX_TX_CTRL & ~ENET_QOS_DMA_CHX_TX_CTRL_TxPBL_MASK; + base->DMA_CH[index].DMA_CHX_TX_CTRL = reg | ENET_QOS_DMA_CHX_TX_CTRL_TxPBL(burstLen & 0x3FU); + + reg = base->DMA_CH[index].DMA_CHX_RX_CTRL & ~ENET_QOS_DMA_CHX_RX_CTRL_RxPBL_MASK; + base->DMA_CH[index].DMA_CHX_RX_CTRL = reg | ENET_QOS_DMA_CHX_RX_CTRL_RxPBL(burstLen & 0x3FU); + } +} + +static void ENET_QOS_SetMTL(ENET_QOS_Type *base, const enet_qos_config_t *config) +{ + assert(config != NULL); + + uint32_t txqOpreg = 0; + uint32_t rxqOpReg = 0; + enet_qos_multiqueue_config_t *multiqCfg = config->multiqueueCfg; + uint8_t index; + + /* Set transmit operation mode. */ + if ((config->specialControl & (uint32_t)kENET_QOS_StoreAndForward) != 0U) + { + txqOpreg = ENET_QOS_MTL_TXQX_OP_MODE_TSF_MASK; + rxqOpReg = ENET_QOS_MTL_RXQX_OP_MODE_RSF_MASK; + } + /* Set transmit operation mode. */ + txqOpreg |= ENET_QOS_MTL_TXQX_OP_MODE_FTQ_MASK; + /* Set receive operation mode. */ + rxqOpReg |= ENET_QOS_MTL_RXQX_OP_MODE_FUP_MASK | ENET_QOS_MTL_RXQX_OP_MODE_RFD(3U) | + ENET_QOS_MTL_RXQX_OP_MODE_RFA(1U) | ENET_QOS_MTL_RXQX_OP_MODE_EHFC_MASK; + + if (multiqCfg == NULL) + { + txqOpreg |= + ENET_QOS_MTL_TXQX_OP_MODE_TQS(((uint32_t)ENET_QOS_MTL_TXFIFOSIZE / (uint32_t)ENET_QOS_FIFOSIZE_UNIT - 1U)); + rxqOpReg |= + ENET_QOS_MTL_RXQX_OP_MODE_RQS(((uint32_t)ENET_QOS_MTL_RXFIFOSIZE / (uint32_t)ENET_QOS_FIFOSIZE_UNIT - 1U)); + base->MTL_QUEUE[0].MTL_TXQX_OP_MODE = txqOpreg | ENET_QOS_MTL_TXQX_OP_MODE_TXQEN((uint32_t)kENET_QOS_DCB_Mode); + base->MTL_QUEUE[0].MTL_RXQX_OP_MODE = rxqOpReg; + } + else + { + /* Set the schedule/arbitration(set for multiple queues). */ + base->MTL_OPERATION_MODE = ENET_QOS_MTL_OPERATION_MODE_SCHALG(multiqCfg->mtltxSche) | + ENET_QOS_MTL_OPERATION_MODE_RAA(multiqCfg->mtlrxSche); + + for (index = 0; index < multiqCfg->txQueueUse; index++) + { + txqOpreg |= ENET_QOS_MTL_TXQX_OP_MODE_TQS( + ((uint32_t)ENET_QOS_MTL_TXFIFOSIZE / ((uint32_t)multiqCfg->txQueueUse * ENET_QOS_FIFOSIZE_UNIT)) - 1U); + base->MTL_QUEUE[index].MTL_TXQX_OP_MODE = + txqOpreg | ENET_QOS_MTL_TXQX_OP_MODE_TXQEN((uint32_t)multiqCfg->txQueueConfig[index].mode); + if (multiqCfg->txQueueConfig[index].mode == kENET_QOS_AVB_Mode) + { + ENET_QOS_AVBConfigure(base, multiqCfg->txQueueConfig[index].cbsConfig, index); + } + else + { + base->MTL_QUEUE[index].MTL_TXQX_QNTM_WGHT = multiqCfg->txQueueConfig[index].weight; + } + } + + volatile uint32_t *mtlrxQuemapReg; + uint8_t configIndex; + for (index = 0; index < multiqCfg->rxQueueUse; index++) + { + rxqOpReg |= ENET_QOS_MTL_RXQX_OP_MODE_RQS( + ((uint32_t)ENET_QOS_MTL_RXFIFOSIZE / ((uint32_t)multiqCfg->rxQueueUse * ENET_QOS_FIFOSIZE_UNIT)) - 1U); + base->MTL_QUEUE[index].MTL_RXQX_OP_MODE = rxqOpReg; + mtlrxQuemapReg = (index < 4U) ? &base->MTL_RXQ_DMA_MAP0 : &base->MTL_RXQ_DMA_MAP1; + configIndex = (index & 0x3U); + *mtlrxQuemapReg &= ~((uint32_t)ENET_QOS_MTL_RXQ_DMA_MAP0_Q0MDMACH_MASK << (8U * configIndex)); + *mtlrxQuemapReg |= (uint32_t)ENET_QOS_MTL_RXQ_DMA_MAP0_Q0MDMACH(multiqCfg->rxQueueConfig[index].mapChannel) + << (8U * configIndex); + } + } +} + +static void ENET_QOS_SetMacControl(ENET_QOS_Type *base, + const enet_qos_config_t *config, + uint8_t *macAddr, + uint8_t macCount) +{ + assert(config != NULL); + + uint32_t reg = 0; + + /* Set Macaddr */ + /* The dma channel 0 is set as to which the rx packet + * whose DA matches the MAC address content is routed. */ + if (macAddr != NULL) + { + for (uint8_t i = 0; i < macCount; i++) + { + ENET_QOS_SetMacAddr(base, macAddr, i); + } + } + + /* Set the receive filter. */ + reg = + ENET_QOS_MAC_PACKET_FILTER_PR(((config->specialControl & (uint32_t)kENET_QOS_PromiscuousEnable) != 0U) ? 1U : + 0U) | + ENET_QOS_MAC_PACKET_FILTER_DBF(((config->specialControl & (uint32_t)kENET_QOS_BroadCastRxDisable) != 0U) ? 1U : + 0U) | + ENET_QOS_MAC_PACKET_FILTER_PM(((config->specialControl & (uint32_t)kENET_QOS_MulticastAllEnable) != 0U) ? 1U : + 0U) | + ENET_QOS_MAC_PACKET_FILTER_HMC(((config->specialControl & (uint32_t)kENET_QOS_HashMulticastEnable) != 0U) ? 1U : + 0U); + base->MAC_PACKET_FILTER = reg; + /* Flow control. */ + if ((config->specialControl & (uint32_t)kENET_QOS_FlowControlEnable) != 0U) + { + base->MAC_RX_FLOW_CTRL = ENET_QOS_MAC_RX_FLOW_CTRL_RFE_MASK | ENET_QOS_MAC_RX_FLOW_CTRL_UP_MASK; + base->MAC_TX_FLOW_CTRL_Q[0] = ENET_QOS_MAC_TX_FLOW_CTRL_Q_PT(config->pauseDuration); + } + + /* Set the 1us ticket. */ + reg = config->csrClock_Hz / ENET_QOS_MICRSECS_ONESECOND - 1U; + base->MAC_ONEUS_TIC_COUNTER = ENET_QOS_MAC_ONEUS_TIC_COUNTER_TIC_1US_CNTR(reg); + + /* Set the speed and duplex. */ + reg = ENET_QOS_MAC_CONFIGURATION_DM(config->miiDuplex) | (uint32_t)config->miiSpeed | + ENET_QOS_MAC_CONFIGURATION_S2KP(((config->specialControl & (uint32_t)kENET_QOS_8023AS2KPacket) != 0U) ? 1U : + 0U); + if (config->miiDuplex == kENET_QOS_MiiHalfDuplex) + { + reg |= ENET_QOS_MAC_CONFIGURATION_IPG(ENET_QOS_HALFDUPLEX_DEFAULTIPG); + } + base->MAC_CONFIGURATION = reg; + + if (config->multiqueueCfg != NULL) + { + reg = 0U; + uint8_t configIndex; + enet_qos_multiqueue_config_t *multiqCfg = config->multiqueueCfg; + uint32_t txQueuePrioMap0 = base->MAC_TXQ_PRTY_MAP0; + uint32_t txQueuePrioMap1 = base->MAC_TXQ_PRTY_MAP1; + uint32_t rxQueuePrioMap0 = base->MAC_RXQ_CTRL[2]; + uint32_t rxQueuePrioMap1 = base->MAC_RXQ_CTRL[3]; + uint32_t rxCtrlReg1 = base->MAC_RXQ_CTRL[1]; + + for (uint8_t index = 0U; index < multiqCfg->txQueueUse; index++) + { + configIndex = index & 0x3U; + + /* Configure tx queue priority. */ + if (index < 4U) + { + txQueuePrioMap0 &= ~((uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK << (8U * configIndex)); + txQueuePrioMap0 |= (uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0(multiqCfg->txQueueConfig[index].priority) + << (8U * configIndex); + } + else + { + txQueuePrioMap1 &= ~((uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0_MASK << (8U * configIndex)); + txQueuePrioMap1 |= (uint32_t)ENET_QOS_MAC_TXQ_PRTY_MAP0_PSTQ0(multiqCfg->txQueueConfig[index].priority) + << (8U * configIndex); + } + } + + for (uint8_t index = 0U; index < multiqCfg->rxQueueUse; index++) + { + configIndex = index & 0x3U; + + /* Configure rx queue priority. */ + if (index < 4U) + { + rxQueuePrioMap0 &= ~((uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0_MASK << (8U * configIndex)); + rxQueuePrioMap0 |= (uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0(multiqCfg->rxQueueConfig[index].priority) + << (8U * configIndex); + } + else + { + rxQueuePrioMap1 &= ~((uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0_MASK << (8U * configIndex)); + rxQueuePrioMap1 |= (uint32_t)ENET_QOS_MAC_RXQ_CTRL_PSRQ0(multiqCfg->rxQueueConfig[index].priority) + << (8U * configIndex); + } + + /* Configure queue enable mode. */ + reg |= ENET_QOS_MAC_RXQ_CTRL_RXQ0EN((uint32_t)multiqCfg->rxQueueConfig[index].mode) << (2U * index); + + /* Configure rx queue routing */ + if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketAVCPQ) != 0U) + { + rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_AVCPQ_MASK; + rxCtrlReg1 |= (ENET_QOS_MAC_RXQ_CTRL_AVCPQ(index) | ENET_QOS_MAC_RXQ_CTRL_TACPQE_MASK); + } + + if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketPTPQ) != 0U) + { + rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_PTPQ_MASK; + rxCtrlReg1 |= ENET_QOS_MAC_RXQ_CTRL_PTPQ(index); + } + + if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketDCBCPQ) != 0U) + { + rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_DCBCPQ_MASK; + rxCtrlReg1 |= ENET_QOS_MAC_RXQ_CTRL_DCBCPQ(index); + } + + if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketUPQ) != 0U) + { + rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_UPQ_MASK; + rxCtrlReg1 |= ENET_QOS_MAC_RXQ_CTRL_UPQ(index); + } + + if (((uint8_t)multiqCfg->rxQueueConfig[index].packetRoute & (uint8_t)kENET_QOS_PacketMCBCQ) != 0U) + { + rxCtrlReg1 &= ~ENET_QOS_MAC_RXQ_CTRL_MCBCQ_MASK; + rxCtrlReg1 |= (ENET_QOS_MAC_RXQ_CTRL_MCBCQ(index) | ENET_QOS_MAC_RXQ_CTRL_MCBCQEN_MASK); + } + } + + base->MAC_TXQ_PRTY_MAP0 = txQueuePrioMap0; + base->MAC_TXQ_PRTY_MAP1 = txQueuePrioMap1; + base->MAC_RXQ_CTRL[2] = rxQueuePrioMap0; + base->MAC_RXQ_CTRL[3] = rxQueuePrioMap1; + base->MAC_RXQ_CTRL[1] = rxCtrlReg1; + } + else + { + /* Configure queue enable mode. */ + reg = ENET_QOS_MAC_RXQ_CTRL_RXQ0EN((uint32_t)kENET_QOS_DCB_Mode); + } + + /* Enable queue. */ + base->MAC_RXQ_CTRL[0] = reg; + + /* Mask MMC counters interrupts as we don't handle + * them in the interrupt handler. + */ + base->MAC_MMC_RX_INTERRUPT_MASK = 0xFFFFFFFFU; + base->MAC_MMC_TX_INTERRUPT_MASK = 0xFFFFFFFFU; + base->MAC_MMC_IPC_RX_INTERRUPT_MASK = 0xFFFFFFFFU; + base->MAC_MMC_FPE_RX_INTERRUPT_MASK = 0xFFFFFFFFU; + base->MAC_MMC_FPE_TX_INTERRUPT_MASK = 0xFFFFFFFFU; +} + +static status_t ENET_QOS_TxDescriptorsInit(ENET_QOS_Type *base, + const enet_qos_buffer_config_t *bufferConfig, + bool intTxEnable, + uint8_t channel) +{ + uint16_t j; + enet_qos_tx_bd_struct_t *txbdPtr; + uint32_t control = intTxEnable ? ENET_QOS_TXDESCRIP_RD_IOC_MASK : 0U; + const enet_qos_buffer_config_t *buffCfg = bufferConfig; + + if (buffCfg == NULL) + { + return kStatus_InvalidArgument; + } + + /* Check the ring length. */ + if (buffCfg->txRingLen < ENET_QOS_MIN_RINGLEN) + { + return kStatus_InvalidArgument; + } + /* Set the tx descriptor start/tail pointer, shall be word aligned. */ + base->DMA_CH[channel].DMA_CHX_TXDESC_LIST_ADDR = + (uint32_t)buffCfg->txDescStartAddrAlign & ENET_QOS_DMA_CHX_TXDESC_LIST_ADDR_TDESLA_MASK; + base->DMA_CH[channel].DMA_CHX_TXDESC_TAIL_PTR = + (uint32_t)buffCfg->txDescTailAddrAlign & ENET_QOS_DMA_CHX_TXDESC_TAIL_PTR_TDTP_MASK; + /* Set the tx ring length. */ + base->DMA_CH[channel].DMA_CHX_TXDESC_RING_LENGTH = + ((uint32_t)buffCfg->txRingLen - 1U) & ENET_QOS_DMA_CHX_TXDESC_RING_LENGTH_TDRL_MASK; + + /* Init the txbdPtr to the transmit descriptor start address. */ + txbdPtr = (enet_qos_tx_bd_struct_t *)(buffCfg->txDescStartAddrAlign); + for (j = 0; j < buffCfg->txRingLen; j++) + { + txbdPtr->buff1Addr = 0; + txbdPtr->buff2Addr = 0; + txbdPtr->buffLen = control; + txbdPtr->controlStat = 0; + txbdPtr++; + } + + return kStatus_Success; +} + +static status_t ENET_QOS_RxDescriptorsInit(ENET_QOS_Type *base, + enet_qos_config_t *config, + const enet_qos_buffer_config_t *bufferConfig, + bool intRxEnable, + uint8_t channel) +{ + uint16_t j; + uint32_t reg; + enet_qos_rx_bd_struct_t *rxbdPtr; + uint16_t index; + bool doubleBuffEnable = ((config->specialControl & (uint32_t)kENET_QOS_DescDoubleBuffer) != 0U) ? true : false; + const enet_qos_buffer_config_t *buffCfg = bufferConfig; + uint32_t control = ENET_QOS_RXDESCRIP_RD_BUFF1VALID_MASK; + + if (buffCfg == NULL) + { + return kStatus_InvalidArgument; + } + + if (intRxEnable) + { + control |= ENET_QOS_RXDESCRIP_RD_IOC_MASK; + } + + if (doubleBuffEnable) + { + control |= ENET_QOS_RXDESCRIP_RD_BUFF2VALID_MASK; + } + + /* Not give ownership to DMA before Rx buffer is ready */ + if ((config->rxBuffAlloc == NULL) || (config->rxBuffFree == NULL)) + { + control |= ENET_QOS_RXDESCRIP_WR_OWN_MASK; + } + + /* Check the ring length. */ + if (buffCfg->rxRingLen < ENET_QOS_MIN_RINGLEN) + { + return kStatus_InvalidArgument; + } + + /* Set the rx descriptor start/tail pointer, shall be word aligned. */ + base->DMA_CH[channel].DMA_CHX_RXDESC_LIST_ADDR = + (uint32_t)buffCfg->rxDescStartAddrAlign & ENET_QOS_DMA_CHX_RXDESC_LIST_ADDR_RDESLA_MASK; + base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = + (uint32_t)buffCfg->rxDescTailAddrAlign & ENET_QOS_DMA_CHX_RXDESC_TAIL_PTR_RDTP_MASK; + base->DMA_CH[channel].DMA_CHX_RXDESC_RING_LENGTH = + ((uint32_t)buffCfg->rxRingLen - 1U) & ENET_QOS_DMA_CHX_RXDESC_RING_LENGTH_RDRL_MASK; + reg = base->DMA_CH[channel].DMA_CHX_RX_CTRL & ~ENET_QOS_DMA_CHX_RX_CTRL_RBSZ_13_y_MASK; + reg |= ENET_QOS_DMA_CHX_RX_CTRL_RBSZ_13_y(buffCfg->rxBuffSizeAlign >> ENET_QOS_RXBUFF_IGNORELSB_BITS); + base->DMA_CH[channel].DMA_CHX_RX_CTRL = reg; + + /* Init the rxbdPtr to the receive descriptor start address. */ + rxbdPtr = (enet_qos_rx_bd_struct_t *)(buffCfg->rxDescStartAddrAlign); + for (j = 0U; j < buffCfg->rxRingLen; j++) + { + if ((config->rxBuffAlloc == NULL) || (config->rxBuffFree == NULL)) + { + if (doubleBuffEnable) + { + index = 2U * j; + } + else + { + index = j; + } + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffCfg->rxBufferStartAddr[index] = + MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBufferStartAddr[index], kMEMORY_Local2DMA); +#endif + rxbdPtr->buff1Addr = buffCfg->rxBufferStartAddr[index]; + + /* The second buffer is set with 0 because it is not required for normal case. */ + if (doubleBuffEnable) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffCfg->rxBufferStartAddr[index + 1U] = + MEMORY_ConvertMemoryMapAddress((uint32_t)buffCfg->rxBufferStartAddr[index + 1U], kMEMORY_Local2DMA); +#endif + rxbdPtr->buff2Addr = buffCfg->rxBufferStartAddr[index + 1U]; + } + else + { + rxbdPtr->buff2Addr = 0; + } + } + + /* Set the valid and DMA own flag.*/ + rxbdPtr->control = control; + rxbdPtr++; + } + + return kStatus_Success; +} + +static status_t ENET_QOS_SetPtp1588(ENET_QOS_Type *base, const enet_qos_config_t *config, uint32_t refClk_Hz) +{ + assert(config != NULL); + assert(config->ptpConfig != NULL); + assert(refClk_Hz != 0U); + + uint32_t control = 0U; + status_t result = kStatus_Success; + enet_qos_ptp_config_t *ptpConfig = config->ptpConfig; + uint32_t ptpClk_Hz = refClk_Hz; + uint32_t ssInc, snsSinc; + + /* Clear the timestamp interrupt first. */ + base->MAC_INTERRUPT_ENABLE &= ~ENET_QOS_MAC_INTERRUPT_ENABLE_TSIE_MASK; + + if (ptpConfig->fineUpdateEnable) + { + control |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCFUPDT_MASK; + ptpClk_Hz = ptpConfig->systemTimeClock_Hz; /* PTP clock 50MHz. */ + } + + /* Enable the IEEE 1588 timestamping and snapshot for event message. */ + control |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_TSIPV4ENA_MASK | + ENET_QOS_MAC_TIMESTAMP_CONTROL_TSIPV6ENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_TSENALL_MASK | + ENET_QOS_MAC_TIMESTAMP_CONTROL_TSEVNTENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_SNAPTYPSEL_MASK | + ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR(ptpConfig->tsRollover); + + if (ptpConfig->ptp1588V2Enable) + { + control |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSVER2ENA_MASK | ENET_QOS_MAC_TIMESTAMP_CONTROL_TSIPENA_MASK; + } + + /* Initialize the sub-second increment register. */ + if (ptpConfig->tsRollover == kENET_QOS_DigitalRollover) + { + ssInc = (uint32_t)(((uint64_t)ENET_QOS_NANOSECS_ONESECOND << 8U) / ptpClk_Hz); + } + else + { + ssInc = (uint32_t)((((uint64_t)ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_TSSS_MASK + 1U) << 8U) / ptpClk_Hz); + } + + snsSinc = ssInc & 0xFFU; + ssInc = (ssInc >> 8U) & 0xFFU; + + base->MAC_TIMESTAMP_CONTROL = control; + + /* Initialize the system timer. */ + base->MAC_SYSTEM_TIME_NANOSECONDS_UPDATE = 0; + + /* Set the second.*/ + base->MAC_SYSTEM_TIME_SECONDS_UPDATE = 0; + base->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS = 0; + + /* Initialize the system timer. */ + base->MAC_TIMESTAMP_CONTROL |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSINIT_MASK; + + while ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSINIT_MASK) != 0U) + { + } + + base->MAC_SUB_SECOND_INCREMENT = + ENET_QOS_MAC_SUB_SECOND_INCREMENT_SSINC(ssInc) | ENET_QOS_MAC_SUB_SECOND_INCREMENT_SNSINC(snsSinc); + + /* Set the initial added value for the fine update. */ + if (ptpConfig->fineUpdateEnable) + { + result = ENET_QOS_Ptp1588CorrectTimerInFine(base, ptpConfig->defaultAddend); + } + + return result; +} + +static inline bool ENET_QOS_TxDirtyRingAvailable(enet_qos_tx_dirty_ring_t *txDirtyRing) +{ + return !txDirtyRing->isFull; +} + +static void ENET_QOS_StoreRxFrameTime(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + enet_qos_rx_bd_struct_t *rxDesc, + enet_qos_ptp_time_t *ts) +{ + assert(ts != NULL); + + uint32_t nanosecond; + + /* Get transmit time stamp second. */ + nanosecond = rxDesc->buff1Addr; + if ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK) == 0U) + { + /* Binary rollover, 0.465ns accuracy. */ + nanosecond = (uint32_t)(((uint64_t)nanosecond * 465U) / 1000U); + } + ts->second = rxDesc->reserved; + ts->nanosecond = nanosecond; +} + +uint32_t ENET_QOS_GetInstance(ENET_QOS_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_enetqosBases); instance++) + { + if (s_enetqosBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_enetqosBases)); + + return instance; +} + +/*! + * brief Gets the ENET default configuration structure. + * + * The purpose of this API is to get the default ENET configure + * structure for ENET_QOS_Init(). User may use the initialized + * structure unchanged in ENET_QOS_Init(), or modify some fields of the + * structure before calling ENET_QOS_Init(). + * Example: + code + enet_qos_config_t config; + ENET_QOS_GetDefaultConfig(&config); + endcode + * param config The ENET mac controller configuration structure pointer. + */ +void ENET_QOS_GetDefaultConfig(enet_qos_config_t *config) +{ + /* Checks input parameter. */ + assert(config != NULL); + + /* Initializes the configure structure to zero. */ + (void)memset(config, 0, sizeof(*config)); + + /* Sets RGMII mode, full duplex, 1000Mbps for MAC and PHY data interface. */ + config->miiMode = kENET_QOS_RgmiiMode; + config->miiSpeed = kENET_QOS_MiiSpeed1000M; + config->miiDuplex = kENET_QOS_MiiFullDuplex; + + /* Sets default configuration for other options. */ + config->specialControl = 0; + config->multiqueueCfg = NULL; + config->pauseDuration = 0; + + config->ptpConfig = NULL; +} + +/*! + * brief Initializes the ENET module. + * + * This function set up the with ENET basic configuration. + * + * param base ENET peripheral base address. + * param config ENET mac configuration structure pointer. + * The "enet_qos_config_t" type mac configuration return from ENET_QOS_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * param macAddr ENET mac address of Ethernet device. This MAC address should be + * provided. + * param refclkSrc_Hz ENET input reference clock. + */ +status_t ENET_QOS_Up( + ENET_QOS_Type *base, const enet_qos_config_t *config, uint8_t *macAddr, uint8_t macCount, uint32_t refclkSrc_Hz) +{ + assert(config != NULL); + status_t result = kStatus_Success; + + /* Initializes the ENET MTL with basic function. */ + ENET_QOS_SetMTL(base, config); + + /* Initializes the ENET MAC with basic function. */ + ENET_QOS_SetMacControl(base, config, macAddr, macCount); + + return result; +} + +/*! + * brief Initializes the ENET module. + * + * This function ungates the module clock and initializes it with the ENET basic + * configuration. + * + * param base ENET peripheral base address. + * param config ENET mac configuration structure pointer. + * The "enet_qos_config_t" type mac configuration return from ENET_QOS_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * param macAddr ENET mac address of Ethernet device. This MAC address should be + * provided. + * param refclkSrc_Hz ENET input reference clock. + */ +status_t ENET_QOS_Init( + ENET_QOS_Type *base, const enet_qos_config_t *config, uint8_t *macAddr, uint8_t macCount, uint32_t refclkSrc_Hz) +{ + assert(config != NULL); + + status_t result = kStatus_Success; + uint32_t instance = ENET_QOS_GetInstance(base); +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Ungate ENET clock. */ + (void)CLOCK_EnableClock(s_enetqosClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* System configure fistly. */ + ENET_QOS_SetSYSControl(config->miiMode); + + /* Initializes the ENET DMA with basic function. */ + ENET_QOS_SetDMAControl(base, config); + + (void)ENET_QOS_Up(base, config, macAddr, macCount, refclkSrc_Hz); + + if (config->ptpConfig != NULL) + { + result = ENET_QOS_SetPtp1588(base, config, refclkSrc_Hz); + } + + return result; +} + +/*! + * brief Stops the ENET module. + + * This function disables the ENET module. + * + * param base ENET peripheral base address. + */ +void ENET_QOS_Down(ENET_QOS_Type *base) +{ + enet_qos_handle_t *handle = s_ENETHandle[ENET_QOS_GetInstance(base)]; + enet_qos_tx_bd_struct_t *txbdPtr; + uint8_t index; + uint32_t primask, j; + + /* Disable all interrupts */ + ENET_QOS_DisableInterrupts(base, 0xFF); + + for (index = 0; index < handle->txQueueUse; index++) + { + enet_qos_tx_bd_ring_t *txBdRing = &handle->txBdRing[index]; + enet_qos_tx_dirty_ring_t *txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[index]; + + /* Clear pending descriptors */ + if (handle->callback != NULL) + { + while (txBdRing->txDescUsed > 0U) + { + enet_qos_frame_info_t *txDirty = &txDirtyRing->txDirtyBase[txDirtyRing->txConsumIdx]; + + txDirty->isTsAvail = false; + + handle->callback(base, handle, kENET_QOS_TxIntEvent, index, handle->userData); + + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed--; + EnableGlobalIRQ(primask); + } + } + + /* Disable Tx DMA */ + base->DMA_CH[index].DMA_CHX_TX_CTRL &= ~ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK; + + /* Flush Tx Queue */ + base->MTL_QUEUE[index].MTL_TXQX_OP_MODE |= ENET_QOS_MTL_TXQX_OP_MODE_FTQ_MASK; + + /* Wait until Tx Queue is empty */ + while ((base->MTL_QUEUE[index].MTL_TXQX_DBG & + (ENET_QOS_MTL_TXQX_DBG_TXQSTS_MASK | ENET_QOS_MTL_TXQX_DBG_PTXQ_MASK)) != 0U) + { + } + + /* Reset hardware ring buffer */ + base->DMA_CH[index].DMA_CHX_TXDESC_LIST_ADDR = + (uint32_t)handle->txBdRing[index].txBdBase & ENET_QOS_DMA_CHX_TXDESC_LIST_ADDR_TDESLA_MASK; + + /* Reset software ring buffer */ + handle->txBdRing[index].txGenIdx = 0; + handle->txBdRing[index].txConsumIdx = 0; + handle->txBdRing[index].txDescUsed = 0; + + handle->txDirtyRing[index].txGenIdx = 0; + handle->txDirtyRing[index].txConsumIdx = 0; + handle->txDirtyRing[index].isFull = false; + + txbdPtr = (enet_qos_tx_bd_struct_t *)(handle->txBdRing[index].txBdBase); + for (j = 0; j < handle->txBdRing[index].txRingLen; j++) + { + txbdPtr->buff1Addr = 0; + txbdPtr->buff2Addr = 0; + txbdPtr->buffLen = 0; + txbdPtr->controlStat = 0; + txbdPtr++; + } + } + + /* Disable MAC Rx/Tx */ + base->MAC_CONFIGURATION &= ~(ENET_QOS_MAC_CONFIGURATION_TE_MASK | ENET_QOS_MAC_CONFIGURATION_RE_MASK); + + /* Disable Rx DMA */ + for (index = 0; index < handle->rxQueueUse; index++) + { + base->DMA_CH[index].DMA_CHX_RX_CTRL &= ~ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK; + } +} + +/*! + * brief Deinitializes the ENET module. + + * This function gates the module clock and disables the ENET module. + * + * param base ENET peripheral base address. + */ +void ENET_QOS_Deinit(ENET_QOS_Type *base) +{ + /* Reset first and wait for the complete + * The reset bit will automatically be cleared after complete. */ + base->DMA_MODE |= ENET_QOS_DMA_MODE_SWR_MASK; + while ((base->DMA_MODE & ENET_QOS_DMA_MODE_SWR_MASK) != 0U) + { + } + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disables the clock source. */ + (void)CLOCK_DisableClock(s_enetqosClock[ENET_QOS_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Initialize for all ENET descriptors. + * + * note This function is do all tx/rx descriptors initialization. Because this API + * read all interrupt registers first and then set the interrupt flag for all descriptos, + * if the interrupt register is set. so the descriptor initialization should be called + * after ENET_QOS_Init(), ENET_QOS_EnableInterrupts() and ENET_QOS_CreateHandle()(if transactional APIs + * are used). + * + * param base ENET peripheral base address. + * param config The configuration for ENET. + * param bufferConfig All buffers configuration. + */ +status_t ENET_QOS_DescriptorInit(ENET_QOS_Type *base, enet_qos_config_t *config, enet_qos_buffer_config_t *bufferConfig) +{ + assert(config != NULL); + assert(bufferConfig != NULL); + + bool intTxEnable = false; + bool intRxEnable = false; + uint8_t ringNum = 1; + uint8_t txQueueUse = 1; + uint8_t rxQueueUse = 1; + uint8_t channel; + + if (config->multiqueueCfg != NULL) + { + ringNum = MAX(config->multiqueueCfg->txQueueUse, config->multiqueueCfg->rxQueueUse); + txQueueUse = config->multiqueueCfg->txQueueUse; + rxQueueUse = config->multiqueueCfg->rxQueueUse; + } + + for (channel = 0; channel < ringNum; channel++) + { + intRxEnable = ((base->DMA_CH[channel].DMA_CHX_INT_EN & ENET_QOS_DMA_CHX_INT_EN_RIE_MASK) != 0U) ? true : false; + intTxEnable = ((base->DMA_CH[channel].DMA_CHX_INT_EN & ENET_QOS_DMA_CHX_INT_EN_TIE_MASK) != 0U) ? true : false; + + if (channel < txQueueUse) + { + if ((ENET_QOS_TxDescriptorsInit(base, bufferConfig, intTxEnable, channel) != kStatus_Success)) + { + return kStatus_Fail; + } + } + + if (channel < rxQueueUse) + { + if ((ENET_QOS_RxDescriptorsInit(base, config, bufferConfig, intRxEnable, channel) != kStatus_Success)) + { + return kStatus_Fail; + } + } + + bufferConfig++; + } + return kStatus_Success; +} + +/*! + * brief Allocates Rx buffers for all BDs. + * It's used for zero copy Rx. In zero copy Rx case, Rx buffers are dynamic. This function + * will populate initial buffers in all BDs for receiving. Then ENET_QOS_GetRxFrame() is used + * to get Rx frame with zero copy, it will allocate new buffer to replace the buffer in BD taken + * by application application should free those buffers after they're used. + * + * note This function should be called after ENET_QOS_CreateHandler() and buffer allocating callback + * function should be ready. + * + * param base ENET_QOS peripheral base address. + * param handle The ENET_QOS handler structure. This is the same handler pointer used in the ENET_QOS_Init. + */ +status_t ENET_QOS_RxBufferAllocAll(ENET_QOS_Type *base, enet_qos_handle_t *handle) +{ + status_t result = kStatus_Success; + enet_qos_rx_bd_struct_t *rxbdPtr; + uint32_t buffAddr; + uint8_t channel; + uint16_t index; + uint16_t j; + + if ((handle->rxBuffAlloc == NULL) || (handle->rxBuffFree == NULL)) + { + return kStatus_ENET_QOS_InitMemoryFail; + } + + for (channel = 0; channel < handle->rxQueueUse; channel++) + { + /* Init the rxbdPtr to the receive descriptor start address. */ + rxbdPtr = handle->rxBdRing[channel].rxBdBase; + for (j = 0U; j < handle->rxBdRing[channel].rxRingLen; j++) + { + if (handle->doubleBuffEnable) + { + index = 2U * j; + } + else + { + index = j; + } + + buffAddr = (uint32_t)(uint32_t *)handle->rxBuffAlloc(base, handle->userData, channel); + if (buffAddr == 0U) + { + result = kStatus_ENET_QOS_InitMemoryFail; + break; + } + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffAddr = MEMORY_ConvertMemoryMapAddress(buffAddr, kMEMORY_Local2DMA); +#endif + rxbdPtr->buff1Addr = buffAddr; + handle->rxBufferStartAddr[channel][index] = buffAddr; + + /* The second buffer is set with 0 because it is not required for normal case. */ + if (handle->doubleBuffEnable) + { + buffAddr = (uint32_t)(uint32_t *)handle->rxBuffAlloc(base, handle->userData, channel); + if (buffAddr == 0U) + { + result = kStatus_ENET_QOS_InitMemoryFail; + break; + } + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffAddr = MEMORY_ConvertMemoryMapAddress(buffAddr, kMEMORY_Local2DMA); +#endif + rxbdPtr->buff2Addr = buffAddr; + handle->rxBufferStartAddr[channel][index + 1U] = buffAddr; + } + else + { + rxbdPtr->buff2Addr = 0; + } + + /* Set the valid and DMA own flag.*/ + rxbdPtr->control |= ENET_QOS_RXDESCRIP_WR_OWN_MASK; + rxbdPtr++; + } + } + + if (result == kStatus_ENET_QOS_InitMemoryFail) + { + ENET_QOS_RxBufferFreeAll(base, handle); + } + + return result; +} + +/*! + * brief Frees Rx buffers in all BDs. + * It's used for zero copy Rx. In zero copy Rx case, Rx buffers are dynamic. This function + * will free left buffers in all BDs. + * + * param base ENET_QOS peripheral base address. + * param handle The ENET_QOS handler structure. This is the same handler pointer used in the ENET_QOS_Init. + */ +void ENET_QOS_RxBufferFreeAll(ENET_QOS_Type *base, enet_qos_handle_t *handle) +{ + uint32_t buffAddr; + uint8_t channel; + uint16_t index; + uint16_t j; + + if (handle->rxBuffFree != NULL) + { + for (channel = 0; channel < handle->rxQueueUse; channel++) + { + for (j = 0U; j < handle->rxBdRing[channel].rxRingLen; j++) + { + if (handle->doubleBuffEnable) + { + index = 2U * j; + } + else + { + index = j; + } + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffAddr = MEMORY_ConvertMemoryMapAddress((uint32_t)handle->rxBufferStartAddr[channel][index], + kMEMORY_DMA2Local); +#else + buffAddr = (uint32_t)handle->rxBufferStartAddr[channel][index]; +#endif + if (buffAddr != 0U) + { + handle->rxBuffFree(base, (void *)(uint32_t *)buffAddr, handle->userData, channel); + } + + /* The second buffer is set with 0 because it is not required for normal case. */ + if (handle->doubleBuffEnable) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffAddr = MEMORY_ConvertMemoryMapAddress((uint32_t)handle->rxBufferStartAddr[channel][index + 1], + kMEMORY_DMA2Local); +#else + buffAddr = (uint32_t)handle->rxBufferStartAddr[channel][index + 1U]; +#endif + if (buffAddr != 0U) + { + handle->rxBuffFree(base, (void *)(uint32_t *)buffAddr, handle->userData, channel); + } + } + } + } + } +} + +/*! + * brief Starts the ENET rx/tx. + * This function enable the tx/rx and starts the rx/tx DMA. + * This shall be set after ENET initialization and before + * starting to receive the data. + * + * param base ENET peripheral base address. + * param rxRingNum The number of the used rx rings. It shall not be + * larger than the ENET_QOS_RING_NUM_MAX(2). If the ringNum is set with + * 1, the ring 0 will be used. + * param txRingNum The number of the used tx rings. It shall not be + * larger than the ENET_QOS_RING_NUM_MAX(2). If the ringNum is set with + * 1, the ring 0 will be used. + * + * note This must be called after all the ENET initilization. + * And should be called when the ENET receive/transmit is required. + */ +void ENET_QOS_StartRxTx(ENET_QOS_Type *base, uint8_t txRingNum, uint8_t rxRingNum) +{ + assert(txRingNum != 0U); + assert(rxRingNum != 0U); + + uint8_t index; + + if (txRingNum > ENET_QOS_RING_NUM_MAX) + { + txRingNum = ENET_QOS_RING_NUM_MAX; + } + if (rxRingNum > ENET_QOS_RING_NUM_MAX) + { + rxRingNum = ENET_QOS_RING_NUM_MAX; + } + /* Start/Acive the DMA first. */ + for (index = 0; index < rxRingNum; index++) + { + base->DMA_CH[index].DMA_CHX_RX_CTRL |= ENET_QOS_DMA_CHX_RX_CTRL_SR_MASK; + } + for (index = 0; index < txRingNum; index++) + { + base->DMA_CH[index].DMA_CHX_TX_CTRL |= ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK; + } + + /* Enable the RX and TX at same time. */ + base->MAC_CONFIGURATION |= (ENET_QOS_MAC_CONFIGURATION_TE_MASK | ENET_QOS_MAC_CONFIGURATION_RE_MASK); +} + +/*! + * brief Enables the ENET DMA and MAC interrupts. + * + * This function enables the ENET interrupt according to the provided mask. The mask + * is a logical OR of enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + * For example, to enable the dma and mac interrupt, do the following. + * code + * ENET_QOS_EnableInterrupts(ENET, kENET_QOS_DmaRx | kENET_QOS_DmaTx | kENET_QOS_MacPmt); + * endcode + * + * param base ENET peripheral base address. + * param mask ENET interrupts to enable. This is a logical OR of both + * enumeration :: enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + */ +void ENET_QOS_EnableInterrupts(ENET_QOS_Type *base, uint32_t mask) +{ + uint32_t interrupt = mask & 0xFFFFU; + uint8_t index; + + /* For dma interrupt. */ + if (interrupt != 0U) + { + for (index = 0; index < ENET_QOS_RING_NUM_MAX; index++) + { + /* Set for all abnormal interrupts. */ + if ((ENET_QOS_ABNORM_INT_MASK & interrupt) != 0U) + { + interrupt |= ENET_QOS_DMA_CHX_INT_EN_AIE_MASK; + } + /* Set for all normal interrupts. */ + if ((ENET_QOS_NORM_INT_MASK & interrupt) != 0U) + { + interrupt |= ENET_QOS_DMA_CHX_INT_EN_NIE_MASK; + } + base->DMA_CH[index].DMA_CHX_INT_EN = interrupt; + } + } + interrupt = mask >> ENET_QOS_MACINT_ENUM_OFFSET; + if (interrupt != 0U) + { + /* MAC interrupt */ + base->MAC_INTERRUPT_ENABLE |= interrupt; + } +} + +/*! + * brief Clears the ENET mac interrupt events status flag. + * + * This function clears enabled ENET interrupts according to the provided mask. The mask + * is a logical OR of enumeration members. See the ref enet_qos_mac_interrupt_enable_t. + * For example, to clear the TX frame interrupt and RX frame interrupt, do the following. + * code + * ENET_QOS_ClearMacInterruptStatus(ENET, kENET_QOS_MacPmt); + * endcode + * + * param base ENET peripheral base address. + * param mask ENET interrupt source to be cleared. + * This is the logical OR of members of the enumeration :: enet_qos_mac_interrupt_enable_t. + */ +void ENET_QOS_ClearMacInterruptStatus(ENET_QOS_Type *base, uint32_t mask) +{ + volatile uint32_t dummy; + + if ((mask & (uint32_t)kENET_QOS_MacTimestamp) != 0U) + { + dummy = base->MAC_TIMESTAMP_STATUS; + } + else if ((mask & (uint32_t)kENET_QOS_MacPmt) != 0U) + { + dummy = base->MAC_PMT_CONTROL_STATUS; + } + else + { + /* Add for avoid the misra 2004 rule 14.10 */ + } + (void)dummy; +} + +/*! + * brief Disables the ENET DMA and MAC interrupts. + * + * This function disables the ENET interrupt according to the provided mask. The mask + * is a logical OR of enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + * For example, to disable the dma and mac interrupt, do the following. + * code + * ENET_QOS_DisableInterrupts(ENET, kENET_QOS_DmaRx | kENET_QOS_DmaTx | kENET_QOS_MacPmt); + * endcode + * + * param base ENET peripheral base address. + * param mask ENET interrupts to disables. This is a logical OR of both + * enumeration :: enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + */ +void ENET_QOS_DisableInterrupts(ENET_QOS_Type *base, uint32_t mask) +{ + uint32_t interrupt = mask & 0xFFFFU; + uint8_t index; + + /* For dma interrupt. */ + if (interrupt != 0U) + { + for (index = 0; index < ENET_QOS_RING_NUM_MAX; index++) + { + /* Set for all abnormal interrupts. */ + if ((ENET_QOS_ABNORM_INT_MASK & interrupt) != 0U) + { + interrupt |= ENET_QOS_DMA_CHX_INT_EN_AIE_MASK; + } + /* Set for all normal interrupts. */ + if ((ENET_QOS_NORM_INT_MASK & interrupt) != 0U) + { + interrupt |= ENET_QOS_DMA_CHX_INT_EN_NIE_MASK; + } + base->DMA_CH[index].DMA_CHX_INT_EN &= ~interrupt; + } + } + interrupt = mask >> ENET_QOS_MACINT_ENUM_OFFSET; + if (interrupt != 0U) + { + /* MAC interrupt */ + base->MAC_INTERRUPT_ENABLE &= ~interrupt; + } +} + +/*! + * @brief Set the second level IRQ handler, allow user to overwrite the default + * second level weak IRQ handler. + * + * @param ISRHandler he handler to install. + */ +void ENET_QOS_SetISRHandler(ENET_QOS_Type *base, enet_qos_isr_t ISRHandler) +{ + /* Update IRQ entry. */ + s_enetqosIsr = ISRHandler; + /* Enable NVIC. */ + (void)EnableIRQ(s_enetqosIrqId[ENET_QOS_GetInstance(base)]); +} + +/*! + * brief Create ENET Handler + * + * This is a transactional API and it's provided to store all datas which are needed + * during the whole transactional process. This API should not be used when you use + * functional APIs to do data tx/rx. This is funtion will store many data/flag for + * transactional use, so all configure API such as ENET_QOS_Init(), ENET_QOS_DescriptorInit(), + * ENET_QOS_EnableInterrupts() etc. + * + * note as our transactional transmit API use the zero-copy transmit buffer. + * so there are two thing we emphasize here: + * 1. tx buffer free/requeue for application should be done in the tx + * interrupt handler. Please set callback: kENET_QOS_TxIntEvent with tx buffer free/requeue + * process APIs. + * 2. the tx interrupt is forced to open. + * + * param base ENET peripheral base address. + * param handle ENET handler. + * param config ENET configuration. + * param bufferConfig ENET buffer configuration. + * param callback The callback function. + * param userData The application data. + */ +void ENET_QOS_CreateHandler(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + enet_qos_config_t *config, + enet_qos_buffer_config_t *bufferConfig, + enet_qos_callback_t callback, + void *userData) +{ + assert(config != NULL); + assert(bufferConfig != NULL); + assert(callback != NULL); + + uint8_t ringNum = 1; + uint8_t count = 0; + uint32_t rxIntEnable = 0; + uint8_t txQueueUse = 1; + uint8_t rxQueueUse = 1; + enet_qos_buffer_config_t *buffConfig = bufferConfig; + + /* Store transfer parameters in handle pointer. */ + (void)memset(handle, 0, sizeof(enet_qos_handle_t)); + + if (config->multiqueueCfg != NULL) + { + txQueueUse = config->multiqueueCfg->txQueueUse; + rxQueueUse = config->multiqueueCfg->rxQueueUse; + ringNum = MAX(txQueueUse, rxQueueUse); + } + + handle->txQueueUse = txQueueUse; + handle->rxQueueUse = rxQueueUse; + + if ((config->specialControl & (uint32_t)kENET_QOS_DescDoubleBuffer) != 0U) + { + handle->doubleBuffEnable = true; + } + + for (count = 0; count < ringNum; count++) + { + if (count < txQueueUse) + { + handle->txBdRing[count].txBdBase = buffConfig->txDescStartAddrAlign; + handle->txBdRing[count].txRingLen = buffConfig->txRingLen; + handle->txBdRing[count].txGenIdx = 0; + handle->txBdRing[count].txConsumIdx = 0; + handle->txBdRing[count].txDescUsed = 0; + + handle->txDirtyRing[count].txDirtyBase = buffConfig->txDirtyStartAddr; + handle->txDirtyRing[count].txRingLen = buffConfig->txRingLen; + handle->txDirtyRing[count].txGenIdx = 0; + handle->txDirtyRing[count].txConsumIdx = 0; + + /* Enable tx interrupt for use transactional API to do tx buffer free/requeue. */ + base->DMA_CH[count].DMA_CHX_INT_EN |= ENET_QOS_DMA_CHX_INT_EN_TIE_MASK | ENET_QOS_DMA_CHX_INT_EN_NIE_MASK; + } + + if (count < rxQueueUse) + { + handle->rxBdRing[count].rxBdBase = buffConfig->rxDescStartAddrAlign; + handle->rxBdRing[count].rxGenIdx = 0; + handle->rxBdRing[count].rxRingLen = buffConfig->rxRingLen; + handle->rxBdRing[count].rxBuffSizeAlign = buffConfig->rxBuffSizeAlign; + + /* Record rx buffer address for re-init Rx buffer descriptor */ + handle->rxBufferStartAddr[count] = buffConfig->rxBufferStartAddr; + + /* Record rx buffer need cache maintain */ + handle->rxMaintainEnable[count] = buffConfig->rxBuffNeedMaintain; + + /* Check if the rx interrrupt is enabled. */ + rxIntEnable |= (base->DMA_CH[count].DMA_CHX_INT_EN & ENET_QOS_DMA_CHX_INT_EN_RIE_MASK); + } + + buffConfig++; + } + + handle->rxintEnable = (rxIntEnable != 0U) ? true : false; + + /* Save the handle pointer in the global variables. */ + s_ENETHandle[ENET_QOS_GetInstance(base)] = handle; + + /* Set Rx alloc/free callback. */ + handle->rxBuffAlloc = config->rxBuffAlloc; + handle->rxBuffFree = config->rxBuffFree; + + /* Set callback and userData. */ + handle->callback = callback; + handle->userData = userData; + + /* Use default ENET_QOS_CommonIRQHandler as default weak IRQ handler. */ + ENET_QOS_SetISRHandler(base, ENET_QOS_CommonIRQHandler); +} + +/*! + * brief Gets the ENET module Mac address. + * + * param base ENET peripheral base address. + * param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + */ +void ENET_QOS_GetMacAddr(ENET_QOS_Type *base, uint8_t *macAddr, uint8_t index) +{ + assert(macAddr != NULL); + + uint32_t address = base->MAC_ADDRESS[index].LOW; + + /* Get from physical address lower register. */ + macAddr[2] = (uint8_t)(0xFFU & (address >> 24U)); + macAddr[3] = (uint8_t)(0xFFU & (address >> 16U)); + macAddr[4] = (uint8_t)(0xFFU & (address >> 8U)); + macAddr[5] = (uint8_t)(0xFFU & address); + + /* Get from physical address high register. */ + address = base->MAC_ADDRESS[index].HIGH; + macAddr[0] = (uint8_t)(0xFFU & (address >> 8U)); + macAddr[1] = (uint8_t)(0xFFU & address); +} + +/*! + * brief Adds the ENET_QOS device to a multicast group. + * + * param base ENET_QOS peripheral base address. + * param address The six-byte multicast group address which is provided by application. + */ +void ENET_QOS_AddMulticastGroup(ENET_QOS_Type *base, uint8_t *address) +{ + assert(address != NULL); + + enet_qos_handle_t *handle = s_ENETHandle[ENET_QOS_GetInstance(base)]; + uint32_t crc = 0xFFFFFFFFU; + uint32_t count1 = 0; + uint32_t count2 = 0; + + /* Calculates the CRC-32 polynomial on the multicast group address. */ + for (count1 = 0; count1 < 6U; count1++) + { + uint8_t c = address[count1]; + for (count2 = 0; count2 < 0x08U; count2++) + { + if (((c ^ crc) & 1U) != 0U) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xEDB88320U; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + /* Calculate bitwise reverse value. */ + crc = ENET_QOS_ReverseBits(~crc); + + /* Get highest 6 bits*/ + crc = crc >> 26U; + + handle->multicastCount[crc]++; + + if (0U != (crc & 0x20U)) + { + base->MAC_HASH_TABLE_REG1 |= (1UL << (crc & 0x1FU)); + } + else + { + base->MAC_HASH_TABLE_REG0 |= (1UL << (crc & 0x1FU)); + } +} + +/*! + * brief Moves the ENET_QOS device from a multicast group. + * + * param base ENET_QOS peripheral base address. + * param address The six-byte multicast group address which is provided by application. + */ +void ENET_QOS_LeaveMulticastGroup(ENET_QOS_Type *base, uint8_t *address) +{ + assert(address != NULL); + + enet_qos_handle_t *handle = s_ENETHandle[ENET_QOS_GetInstance(base)]; + uint32_t crc = 0xFFFFFFFFU; + uint32_t count1 = 0; + uint32_t count2 = 0; + + /* Calculates the CRC-32 polynomial on the multicast group address. */ + for (count1 = 0; count1 < 6U; count1++) + { + uint8_t c = address[count1]; + for (count2 = 0; count2 < 0x08U; count2++) + { + if (((c ^ crc) & 1U) != 0U) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xEDB88320U; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + /* Calculate bitwise reverse value. */ + crc = ENET_QOS_ReverseBits(~crc); + + /* Get highest 6 bits*/ + crc = crc >> 26U; + + handle->multicastCount[crc]--; + + /* Set the hash table if no collisions */ + if (0U == handle->multicastCount[crc]) + { + if (0U != (crc & 0x20U)) + { + base->MAC_HASH_TABLE_REG1 &= ~((1UL << (crc & 0x1FU))); + } + else + { + base->MAC_HASH_TABLE_REG0 &= ~((1UL << (crc & 0x1FU))); + } + } +} + +/*! + * brief Sets the ENET SMI(serial management interface)- MII management interface. + * + * param base ENET peripheral base address. + */ +void ENET_QOS_SetSMI(ENET_QOS_Type *base, uint32_t csrClock_Hz) +{ + uint32_t crDiv = 0; + uint32_t srcClock_Hz = csrClock_Hz / 1000000U; + + assert((srcClock_Hz >= 20U) && (srcClock_Hz < 800U)); + + if (srcClock_Hz < 35U) + { + crDiv = 2; + } + else if (srcClock_Hz < 60U) + { + crDiv = 3; + } + else if (srcClock_Hz < 100U) + { + crDiv = 0; + } + else if (srcClock_Hz < 150U) + { + crDiv = 1; + } + else if (srcClock_Hz < 250U) + { + crDiv = 4; + } + else if (srcClock_Hz < 300U) + { + crDiv = 5; + } + else if (srcClock_Hz < 500U) + { + crDiv = 6; + } + else if (srcClock_Hz < 800U) + { + crDiv = 7; + } + else + { + /* Empty else */ + } + + base->MAC_MDIO_ADDRESS = ENET_QOS_MAC_MDIO_ADDRESS_CR(crDiv); +} + +/*! + * brief Starts a SMI write command. + * It supports MDIO IEEE802.3 Clause 22. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. + * param data The data written to PHY. + */ +void ENET_QOS_StartSMIWrite(ENET_QOS_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ + uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK; + + /* Build MII write command. */ + base->MAC_MDIO_ADDRESS = reg | (uint32_t)kENET_QOS_MiiWriteFrame | ENET_QOS_MAC_MDIO_ADDRESS_PA(phyAddr) | + ENET_QOS_MAC_MDIO_ADDRESS_RDA(phyReg); + base->MAC_MDIO_DATA = data; + base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK; +} + +/*! + * brief Starts an SMI read command. + * It supports MDIO IEEE802.3 Clause 22. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param phyReg The PHY register. + */ +void ENET_QOS_StartSMIRead(ENET_QOS_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK; + + /* Build MII read command. */ + base->MAC_MDIO_ADDRESS = reg | (uint32_t)kENET_QOS_MiiReadFrame | ENET_QOS_MAC_MDIO_ADDRESS_PA(phyAddr) | + ENET_QOS_MAC_MDIO_ADDRESS_RDA(phyReg); + base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK; +} + +/*! + * brief Starts a SMI write command. + * It supports MDIO IEEE802.3 Clause 45. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param device The PHY device type. + * param phyReg The PHY register address. + * param data The data written to PHY. + */ +void ENET_QOS_StartExtC45SMIWrite( + ENET_QOS_Type *base, uint32_t phyAddr, uint32_t device, uint32_t phyReg, uint32_t data) +{ + uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK; + + /* Build MII write command. */ + base->MAC_MDIO_ADDRESS = reg | ENET_QOS_MAC_MDIO_ADDRESS_C45E_MASK | (uint32_t)kENET_QOS_MiiWriteFrame | + ENET_QOS_MAC_MDIO_ADDRESS_PA(phyAddr) | ENET_QOS_MAC_MDIO_ADDRESS_RDA(device); + base->MAC_MDIO_DATA = data | ENET_QOS_MAC_MDIO_DATA_RA(phyReg); + base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK; +} + +/*! + * brief Starts a SMI write command. + * It supports MDIO IEEE802.3 Clause 45. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * param base ENET peripheral base address. + * param phyAddr The PHY address. + * param device The PHY device type. + * param phyReg The PHY register address. + */ +void ENET_QOS_StartExtC45SMIRead(ENET_QOS_Type *base, uint32_t phyAddr, uint32_t device, uint32_t phyReg) +{ + uint32_t reg = base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_CR_MASK; + + /* Build MII read command. */ + base->MAC_MDIO_ADDRESS = reg | ENET_QOS_MAC_MDIO_ADDRESS_C45E_MASK | (uint32_t)kENET_QOS_MiiReadFrame | + ENET_QOS_MAC_MDIO_ADDRESS_PA(phyAddr) | ENET_QOS_MAC_MDIO_ADDRESS_RDA(device); + base->MAC_MDIO_DATA = ENET_QOS_MAC_MDIO_DATA_RA(phyReg); + base->MAC_MDIO_ADDRESS |= ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK; +} + +/*! + * brief Set the MAC to enter into power down mode. + * the remote power wake up frame and magic frame can wake up + * the ENET from the power down mode. + * + * param base ENET peripheral base address. + * param wakeFilter The wakeFilter provided to configure the wake up frame fitlter. + * Set the wakeFilter to NULL is not required. But if you have the filter requirement, + * please make sure the wakeFilter pointer shall be eight continous + * 32-bits configuration. + */ +void ENET_QOS_EnterPowerDown(ENET_QOS_Type *base, uint32_t *wakeFilter) +{ + uint8_t index; + uint32_t *reg = wakeFilter; + + /* Disable the tx dma. */ + base->DMA_CH[0].DMA_CHX_TX_CTRL &= ~ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK; + base->DMA_CH[1].DMA_CHX_TX_CTRL &= ~ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK; + + /* Disable the mac tx/rx. */ + base->MAC_CONFIGURATION &= ~(ENET_QOS_MAC_CONFIGURATION_RE_MASK | ENET_QOS_MAC_CONFIGURATION_TE_MASK); + /* Enable the remote wakeup packet and enable the power down mode. */ + if (wakeFilter != NULL) + { + for (index = 0; index < ENET_QOS_WAKEUPFILTER_NUM; index++) + { + base->MAC_RWK_PACKET_FILTER = *reg; + reg++; + } + } + base->MAC_PMT_CONTROL_STATUS = ENET_QOS_MAC_PMT_CONTROL_STATUS_MGKPKTEN_MASK | + ENET_QOS_MAC_PMT_CONTROL_STATUS_RWKPKTEN_MASK | + ENET_QOS_MAC_PMT_CONTROL_STATUS_PWRDWN_MASK; + + /* Enable the MAC rx. */ + base->MAC_CONFIGURATION |= ENET_QOS_MAC_CONFIGURATION_RE_MASK; +} + +/*! + * brief Enable/Disable Rx parser, please notice that for enable/disable Rx Parser, + * should better disable Receive first. + * + * param base ENET_QOS peripheral base address. + * param enable Enable/Disable Rx parser function + */ +status_t ENET_QOS_EnableRxParser(ENET_QOS_Type *base, bool enable) +{ + status_t result = kStatus_Success; + + if (enable) + { + base->MTL_OPERATION_MODE |= ENET_QOS_MTL_OPERATION_MODE_FRPE_MASK; + } + else + { + base->MTL_OPERATION_MODE &= ~ENET_QOS_MTL_OPERATION_MODE_FRPE_MASK; + result = ENET_QOS_PollStatusFlag(&(base->MTL_RXP_CONTROL_STATUS), ENET_QOS_MTL_RXP_CONTROL_STATUS_RXPI_MASK, + ENET_QOS_MTL_RXP_CONTROL_STATUS_RXPI_MASK); + } + + return result; +} + +/*! + * brief Gets the size of the read frame. + * This function gets a received frame size from the ENET buffer descriptors. + * note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS. + * After calling ENET_QOS_GetRxFrameSize, ENET_QOS_ReadFrame() should be called to update the + * receive buffers If the result is not "kStatus_ENET_QOS_RxFrameEmpty". + * + * param handle The ENET handler structure. This is the same handler pointer used in the ENET_QOS_Init. + * param length The length of the valid frame received. + * param channel The DMAC channel for the rx. + * retval kStatus_ENET_QOS_RxFrameEmpty No frame received. Should not call ENET_QOS_ReadFrame to read frame. + * retval kStatus_ENET_QOS_RxFrameError Data error happens. ENET_QOS_ReadFrame should be called with NULL data + * and NULL length to update the receive buffers. + * retval kStatus_Success Receive a frame Successfully then the ENET_QOS_ReadFrame + * should be called with the right data buffer and the captured data length input. + */ +status_t ENET_QOS_GetRxFrameSize(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint32_t *length, uint8_t channel) +{ + assert(handle != NULL); + assert(length != NULL); + + enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel]; + enet_qos_rx_bd_struct_t *rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + uint16_t index = rxBdRing->rxGenIdx; + uint32_t control = rxDesc->control; + + /* Reset the length to zero. */ + *length = 0; + + if ((control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U) + { + return kStatus_ENET_QOS_RxFrameEmpty; + } + else + { + do + { + /* Application owns the buffer descriptor, get the length. */ + if ((control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U) + { + if ((control & ENET_QOS_RXDESCRIP_WR_ERRSUM_MASK) != 0U) + { + return kStatus_ENET_QOS_RxFrameError; + } + *length = (control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK) - ENET_QOS_FCS_LEN; + return kStatus_Success; + } + + index = ENET_QOS_IncreaseIndex(index, rxBdRing->rxRingLen); + rxDesc = &rxBdRing->rxBdBase[index]; + control = rxDesc->control; + } while (index != rxBdRing->rxGenIdx); + + return kStatus_ENET_QOS_RxFrameError; + } +} + +static void ENET_QOS_DropFrame(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint8_t channel) +{ + enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel]; + enet_qos_rx_bd_struct_t *rxDesc; + uint16_t index = rxBdRing->rxGenIdx; + bool tsAvailable = false; + uint32_t buff1Addr = 0; + uint32_t buff2Addr = 0; + + /* Not check DMA ownership here, assume there's at least one valid frame left in BD ring */ + do + { + /* Get the control flag. */ + rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + + if (!handle->doubleBuffEnable) + { + buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable, + handle->doubleBuffEnable); + } + else + { + buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx]; + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + } + + rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + + /* Find the last buffer descriptor for the frame. */ + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U) + { + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_RS1V_MASK) != 0U) + { + if ((rxDesc->reserved & ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK) != 0U) + { + tsAvailable = true; + } + } + + /* Reinit for the context descriptor which has been updated by DMA. */ + rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + + if (tsAvailable && ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) != 0U)) + { + if (!handle->doubleBuffEnable) + { + buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable, + handle->doubleBuffEnable); + } + else + { + buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx]; + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + } + rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + } + break; + } + } while (rxBdRing->rxGenIdx != index); + + /* Always try to start receive, in case it had stopped */ + base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = (uint32_t)(uint8_t *)&rxBdRing->rxBdBase[rxBdRing->rxRingLen]; +} + +/*! + * brief Reads a frame from the ENET device. + * This function reads a frame from the ENET DMA descriptors. + * The ENET_QOS_GetRxFrameSize should be used to get the size of the prepared data buffer. + * For example use rx dma channel 0: + * code + * uint32_t length; + * enet_qos_handle_t g_handle; + * enet_qos_ptp_time_t ts; + * status = ENET_QOS_GetRxFrameSize(&g_handle, &length, 0); + * if (length != 0) + * { + * uint8_t *data = memory allocate interface; + * if (!data) + * { + * ENET_QOS_ReadFrame(ENET, &g_handle, NULL, 0, 0, &ts); + * } + * else + * { + * status = ENET_QOS_ReadFrame(ENET, &g_handle, data, length, 0, &ts); + * } + * } + * else if (status == kStatus_ENET_QOS_RxFrameError) + * { + * ENET_QOS_ReadFrame(ENET, &g_handle, NULL, 0, 0, &ts); + * } + * endcode + * param base ENET peripheral base address. + * param handle The ENET handler structure. This is the same handler pointer used in the ENET_QOS_Init. + * param data The data buffer provided by user to store the frame which memory size should be at least "length". + * param length The size of the data buffer which is still the length of the received frame. + * param channel The rx DMA channel. shall not be larger than 2. + * return The execute status, successful or failure. + */ +status_t ENET_QOS_ReadFrame(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + uint8_t *data, + uint32_t length, + uint8_t channel, + enet_qos_ptp_time_t *ts) +{ + assert(handle != NULL); + assert(channel < handle->rxQueueUse); + + uint32_t len = 0; + uint32_t offset = 0; + uint32_t control; + bool isLastBuff = false; + enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel]; + enet_qos_rx_bd_struct_t *rxDesc; + status_t result = kStatus_Fail; + uint32_t buff1Addr = 0; /*!< Buffer 1 address */ + uint32_t buff2Addr = 0; /*!< Buffer 2 or next descriptor address */ + + bool tsAvailable = false; + + /* For data-NULL input, only update the buffer descriptor. */ + if (data == NULL) + { + ENET_QOS_DropFrame(base, handle, channel); + result = kStatus_Success; + } + else + { + while ((!isLastBuff)) + { + /* The last buffer descriptor of a frame. */ + rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + control = rxDesc->control; + + if (!handle->doubleBuffEnable) + { + buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx]; + if (handle->rxMaintainEnable[channel]) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local), + rxBdRing->rxBuffSizeAlign); +#else + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign); +#endif + } + } + else + { + buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx]; + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; + if (handle->rxMaintainEnable[channel]) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local), + rxBdRing->rxBuffSizeAlign); + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local), + rxBdRing->rxBuffSizeAlign); +#else + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign); + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(buff2Addr, rxBdRing->rxBuffSizeAlign); +#endif + } + } + + rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + + if ((control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U) + { + /* This is a valid frame. */ + isLastBuff = true; + + /* Remove FCS */ + len = (control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK) - ENET_QOS_FCS_LEN; + + if (length == len) + { + /* Copy the frame to user's buffer. */ + len -= offset; + + if (len > rxBdRing->rxBuffSizeAlign) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + (void)memcpy((void *)&data[offset], + (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local), + rxBdRing->rxBuffSizeAlign); +#else + (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff1Addr, rxBdRing->rxBuffSizeAlign); +#endif + offset += rxBdRing->rxBuffSizeAlign; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + (void)memcpy((void *)&data[offset], + (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local), + len - rxBdRing->rxBuffSizeAlign); +#else + (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff2Addr, + len - rxBdRing->rxBuffSizeAlign); +#endif + } + else + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + (void)memcpy((void *)&data[offset], + (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local), + len); +#else + (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff1Addr, len); +#endif + } + + result = kStatus_Success; + } + + if ((rxDesc->reserved & ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK) != 0U) + { + tsAvailable = true; + } + /* Updates the receive buffer descriptors. */ + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + /* Store the rx timestamp which is in the next buffer descriptor of the last + * descriptor of a frame. */ + rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + control = rxDesc->control; + + /* If tsAvailable is true, a context descriptor is expected but might not be yet + * available. + */ + if (tsAvailable) + { + uint8_t retryTimes = 10; + + while (((control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U) || + ((control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) == 0U)) + { + SDK_DelayAtLeastUs(1U, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); + if (0U == retryTimes--) + { + assert(false); + } + control = rxDesc->control; + } + } + + /* Reinit for the context descritor which has been updated by DMA. */ + if ((control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) != 0U) + { + if (tsAvailable && (NULL != ts)) + { + ENET_QOS_StoreRxFrameTime(base, handle, rxDesc, ts); + } + + if (!handle->doubleBuffEnable) + { + buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable, + handle->doubleBuffEnable); + } + else + { + buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx]; + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + } + rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + } + } + else + { + /* Store a frame on several buffer descriptors. */ + isLastBuff = false; + /* Length check. */ + if (offset >= length) + { + /* Updates the receive buffer descriptors. */ + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + break; + } + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + (void)memcpy((void *)&data[offset], + (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local), + rxBdRing->rxBuffSizeAlign); +#else + (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff1Addr, rxBdRing->rxBuffSizeAlign); +#endif + + offset += rxBdRing->rxBuffSizeAlign; + if (buff2Addr != 0U) + { +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + (void)memcpy((void *)&data[offset], + (void *)(uint8_t *)MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local), + rxBdRing->rxBuffSizeAlign); +#else + (void)memcpy((void *)&data[offset], (void *)(uint8_t *)buff2Addr, rxBdRing->rxBuffSizeAlign); +#endif + offset += rxBdRing->rxBuffSizeAlign; + } + + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + } + } + + /* Always try to start receive, in case it had stopped */ + base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = (uint32_t)(uint8_t *)&rxBdRing->rxBdBase[rxBdRing->rxRingLen]; + } + + return result; +} + +/*! + * brief Updates the buffers and the own status for a given rx descriptor. + * This function is a low level functional API to Updates the + * buffers and the own status for a given rx descriptor. + * + * param rxDesc The given rx descriptor. + * param buffer1 The first buffer address in the descriptor. + * param buffer2 The second buffer address in the descriptor. + * param intEnable Interrupt enable flag. + * param doubleBuffEnable The double buffer enable flag. + * + * note This must be called after all the ENET initilization. + * And should be called when the ENET receive/transmit is required. + */ +void ENET_QOS_UpdateRxDescriptor( + enet_qos_rx_bd_struct_t *rxDesc, void *buffer1, void *buffer2, bool intEnable, bool doubleBuffEnable) +{ + assert(rxDesc != NULL); + uint32_t control = ENET_QOS_RXDESCRIP_RD_OWN_MASK | ENET_QOS_RXDESCRIP_RD_BUFF1VALID_MASK; + + if (intEnable) + { + control |= ENET_QOS_RXDESCRIP_RD_IOC_MASK; + } + + if (doubleBuffEnable) + { + control |= ENET_QOS_RXDESCRIP_RD_BUFF2VALID_MASK; + } + + /* Update the buffer if needed. */ + if (buffer1 != NULL) + { + rxDesc->buff1Addr = (uint32_t)(uint8_t *)buffer1; + } + if (buffer2 != NULL) + { + rxDesc->buff2Addr = (uint32_t)(uint8_t *)buffer2; + } + else + { + rxDesc->buff2Addr = 0; + } + + rxDesc->reserved = 0; + + /* Add a data barrier to be sure that the address is written before the + ownership bit status. */ + __DMB(); + + rxDesc->control = control; +} + +/*! + * brief Setup a given tx descriptor. + * This function is a low level functional API to setup or prepare + * a given tx descriptor. + * + * param txDesc The given tx descriptor. + * param buffer1 The first buffer address in the descriptor. + * param bytes1 The bytes in the fist buffer. + * param buffer2 The second buffer address in the descriptor. + * param bytes1 The bytes in the second buffer. + * param framelen The length of the frame to be transmitted. + * param intEnable Interrupt enable flag. + * param tsEnable The timestamp enable. + * param flag The flag of this tx desciriptor, see "enet_qos_desc_flag" . + * param slotNum The slot num used for AV only. + * + * note This must be called after all the ENET initilization. + * And should be called when the ENET receive/transmit is required. + * Transmit buffers are 'zero-copy' buffers, so the buffer must remain in + * memory until the packet has been fully transmitted. The buffers + * should be free or requeued in the transmit interrupt irq handler. + */ +void ENET_QOS_SetupTxDescriptor(enet_qos_tx_bd_struct_t *txDesc, + void *buffer1, + uint32_t bytes1, + void *buffer2, + uint32_t bytes2, + uint32_t framelen, + bool intEnable, + bool tsEnable, + enet_qos_desc_flag flag, + uint8_t slotNum) +{ + uint32_t control = ENET_QOS_TXDESCRIP_RD_BL1(bytes1) | ENET_QOS_TXDESCRIP_RD_BL2(bytes2); + + if (tsEnable) + { + control |= ENET_QOS_TXDESCRIP_RD_TTSE_MASK; + } + else + { + control &= ~ENET_QOS_TXDESCRIP_RD_TTSE_MASK; + } + + if (intEnable) + { + control |= ENET_QOS_TXDESCRIP_RD_IOC_MASK; + } + else + { + control &= ~ENET_QOS_TXDESCRIP_RD_IOC_MASK; + } + +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buffer1 = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)buffer1, kMEMORY_Local2DMA); + buffer2 = (void *)(uint32_t *)MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)buffer2, kMEMORY_Local2DMA); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + + /* Preare the descriptor for transmit. */ + txDesc->buff1Addr = (uint32_t)(uint8_t *)buffer1; + txDesc->buff2Addr = (uint32_t)(uint8_t *)buffer2; + txDesc->buffLen = control; + + /* Make sure all fields of descriptor are written before setting ownership */ + __DMB(); + + control = ENET_QOS_TXDESCRIP_RD_FL(framelen) | ENET_QOS_TXDESCRIP_RD_LDFD(flag) | ENET_QOS_TXDESCRIP_RD_OWN_MASK; + + txDesc->controlStat = control; + + /* Make sure the descriptor is written in memory (before MAC starts checking it) */ + __DSB(); +} + +/*! + * brief Reclaim tx descriptors. + * This function is used to update the tx descriptor status and + * store the tx timestamp when the 1588 feature is enabled. + * This is called by the transmit interupt IRQ handler after the + * complete of a frame transmission. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_QOS_Init. + * param channel The tx DMA channnel. + * + */ +void ENET_QOS_ReclaimTxDescriptor(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint8_t channel) +{ + enet_qos_tx_bd_ring_t *txBdRing = &handle->txBdRing[channel]; + enet_qos_tx_bd_struct_t *txDesc = &txBdRing->txBdBase[txBdRing->txConsumIdx]; + enet_qos_tx_dirty_ring_t *txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[channel]; + enet_qos_frame_info_t *txDirty = NULL; + uint32_t control, primask; + + control = txDesc->controlStat; + + /* Need to update the first index for transmit buffer free. */ + while ((txBdRing->txDescUsed > 0U) && (0U == (control & ENET_QOS_TXDESCRIP_RD_OWN_MASK))) + { + if ((control & ENET_QOS_TXDESCRIP_RD_LD_MASK) != 0U) + { + if (ENET_QOS_TxDirtyRingAvailable(txDirtyRing)) + { + txDirty = &txDirtyRing->txDirtyBase[txBdRing->txConsumIdx]; + txDirtyRing->txGenIdx = ENET_QOS_IncreaseIndex(txDirtyRing->txGenIdx, txDirtyRing->txRingLen); + if (txDirtyRing->txGenIdx == txDirtyRing->txConsumIdx) + { + txDirtyRing->isFull = true; + } + + if ((control & ENET_QOS_TXDESCRIP_WB_TTSS_MASK) != 0U) + { + enet_qos_ptp_time_t *ts = &txDirty->timeStamp; + uint32_t nanosecond; + /* Get transmit time stamp second. */ + nanosecond = txDesc->buff1Addr; + txDirty->isTsAvail = true; + if (0U == (base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK)) + { + /* Binary rollover, 0.465ns accuracy. */ + nanosecond = (nanosecond * 465U) / 1000U; + } + ts->second = txDesc->buff2Addr; + ts->nanosecond = nanosecond; + } + else + { + txDirty->isTsAvail = false; + } + } + } + + /* For tx buffer free or requeue for each descriptor. + * The tx interrupt callback should free/requeue the tx buffer. */ + if (handle->callback != NULL) + { + handle->callback(base, handle, kENET_QOS_TxIntEvent, channel, handle->userData); + } + + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed--; + EnableGlobalIRQ(primask); + + /* Update the txConsumIdx/txDesc. */ + txBdRing->txConsumIdx = ENET_QOS_IncreaseIndex(txBdRing->txConsumIdx, txBdRing->txRingLen); + txDesc = &txBdRing->txBdBase[txBdRing->txConsumIdx]; + control = txDesc->controlStat; + } +} + +/*! + * brief Transmits an ENET frame. + * note The CRC is automatically appended to the data. Input the data + * to send without the CRC. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_QOS_Init. + * param data The data buffer provided by user to be send. + * param length The length of the data to be send. + * param channel Channel to send the frame, same with queue index. + * param isNeedTs True means save timestamp + * param context pointer to user context to be kept in the tx dirty frame information. + * retval kStatus_Success Send frame succeed. + * retval kStatus_ENET_QOS_TxFrameBusy Transmit buffer descriptor is busy under transmission. + * The transmit busy happens when the data send rate is over the MAC capacity. + * The waiting mechanism is recommended to be added after each call return with + * kStatus_ENET_QOS_TxFrameBusy. + */ +status_t ENET_QOS_SendFrame(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + uint8_t *data, + uint32_t length, + uint8_t channel, + bool isNeedTs, + void *context) +{ + assert(handle != NULL); + assert(data != NULL); + assert(channel < handle->txQueueUse); + + enet_qos_tx_bd_ring_t *txBdRing; + enet_qos_tx_bd_struct_t *txDesc; + enet_qos_tx_dirty_ring_t *txDirtyRing; + enet_qos_frame_info_t *txDirty; + uint32_t primask; + + if (length > 2U * ENET_QOS_TXDESCRIP_RD_BL1_MASK) + { + return kStatus_ENET_QOS_TxFrameOverLen; + } + + /* Check if the DMA owns the descriptor. */ + txBdRing = (enet_qos_tx_bd_ring_t *)&handle->txBdRing[channel]; + txDesc = &txBdRing->txBdBase[txBdRing->txGenIdx]; + if (txBdRing->txRingLen == txBdRing->txDescUsed) + { + return kStatus_ENET_QOS_TxFrameBusy; + } + + txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[channel]; + txDirty = &txDirtyRing->txDirtyBase[txBdRing->txGenIdx]; + txDirty->context = context; + + /* Fill the descriptor. */ + if (length <= ENET_QOS_TXDESCRIP_RD_BL1_MASK) + { + ENET_QOS_SetupTxDescriptor(txDesc, data, length, NULL, 0, length, true, isNeedTs, kENET_QOS_FirstLastFlag, 0); + } + else + { + ENET_QOS_SetupTxDescriptor(txDesc, data, ENET_QOS_TXDESCRIP_RD_BL1_MASK, &data[ENET_QOS_TXDESCRIP_RD_BL1_MASK], + (length - ENET_QOS_TXDESCRIP_RD_BL1_MASK), length, true, isNeedTs, + kENET_QOS_FirstLastFlag, 0); + } + + /* Increase the index. */ + txBdRing->txGenIdx = ENET_QOS_IncreaseIndex(txBdRing->txGenIdx, txBdRing->txRingLen); + /* Disable interrupt first and then enable interrupt to avoid the race condition. */ + primask = DisableGlobalIRQ(); + txBdRing->txDescUsed++; + EnableGlobalIRQ(primask); + + /* Update the transmit tail address. */ + txDesc = &txBdRing->txBdBase[txBdRing->txGenIdx]; + if (txBdRing->txGenIdx == 0U) + { + txDesc = &txBdRing->txBdBase[txBdRing->txRingLen]; + } + base->DMA_CH[channel].DMA_CHX_TXDESC_TAIL_PTR = (uint32_t)txDesc & ~ENET_QOS_ADDR_ALIGNMENT; + + return kStatus_Success; +} + +/*! + * brief Gets the sent frame. + * + * This function is used to get the sent frame for timestamp and buffer clean operation. + * + * param handle The ENET handler pointer.This is the same state pointer used in + * ENET_QOS_Init. + * param txFrame Input parameter, pointer to enet_qos_frame_info_t for saving read out frame information. + * param channel Read out frame from specified channel. + */ +void ENET_QOS_GetTxFrame(enet_qos_handle_t *handle, enet_qos_frame_info_t *txFrame, uint8_t channel) +{ + assert(handle != NULL); + assert(channel < handle->txQueueUse); + + enet_qos_tx_dirty_ring_t *txDirtyRing = (enet_qos_tx_dirty_ring_t *)&handle->txDirtyRing[channel]; + enet_qos_frame_info_t *txDirty = &txDirtyRing->txDirtyBase[txDirtyRing->txConsumIdx]; + + (void)memcpy(txFrame, txDirty, sizeof(enet_qos_frame_info_t)); + + txDirtyRing->isFull = false; + txDirtyRing->txConsumIdx = ENET_QOS_IncreaseIndex(txDirtyRing->txConsumIdx, txDirtyRing->txRingLen); +} + +static inline void ENET_QOS_GetRxFrameErr(enet_qos_rx_bd_struct_t *rxDesc, enet_qos_rx_frame_error_t *rxFrameError) +{ + uint32_t rdes2 = rxDesc->buff2Addr; + uint32_t rdes3 = rxDesc->control; + + (void)memset(rxFrameError, 0, sizeof(enet_qos_rx_frame_error_t)); + + if ((rdes2 & ENET_QOS_RXDESCRIP_WR_SA_FAILURE_MASK) != 0U) + { + rxFrameError->rxSrcAddrFilterErr = true; + } + if ((rdes2 & ENET_QOS_RXDESCRIP_WR_DA_FAILURE_MASK) != 0U) + { + rxFrameError->rxDstAddrFilterErr = true; + } + if ((rdes3 & ENET_QOS_RXDESCRIP_WR_DE_MASK) != 0U) + { + rxFrameError->rxDstAddrFilterErr = true; + } + if ((rdes3 & ENET_QOS_RXDESCRIP_WR_RE_MASK) != 0U) + { + rxFrameError->rxReceiveErr = true; + } + if ((rdes3 & ENET_QOS_RXDESCRIP_WR_OE_MASK) != 0U) + { + rxFrameError->rxOverFlowErr = true; + } + if ((rdes3 & ENET_QOS_RXDESCRIP_WR_RWT_MASK) != 0U) + { + rxFrameError->rxWatchDogErr = true; + } + if ((rdes3 & ENET_QOS_RXDESCRIP_WR_GP_MASK) != 0U) + { + rxFrameError->rxGaintPacketErr = true; + } + if ((rdes3 & ENET_QOS_RXDESCRIP_WR_CRC_MASK) != 0U) + { + rxFrameError->rxCrcErr = true; + } +} + +/*! + * brief Receives one frame in specified BD ring with zero copy. + * + * This function will use the user-defined allocate and free callback. Every time application gets one frame through + * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application. + * note This function will drop current frame and update related BDs as available for DMA if new buffers allocating + * fails. Application must provide a memory pool including at least BD number + 1 buffers(+2 if enable double buffer) + * to make this function work normally. If user calls this function in Rx interrupt handler, be careful that this + * function makes Rx BD ready with allocating new buffer(normal) or updating current BD(out of memory). If there's + * always new Rx frame input, Rx interrupt will be triggered forever. Application need to disable Rx interrupt according + * to specific design in this case. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * param rxFrame The received frame information structure provided by user. + * param ringId The ring index or ring number. + * retval kStatus_Success Succeed to get one frame and allocate new memory for Rx buffer. + * retval kStatus_ENET_QOS_RxFrameEmpty There's no Rx frame in the BD. + * retval kStatus_ENET_QOS_RxFrameError There's issue in this receiving. + * retval kStatus_ENET_QOS_RxFrameDrop There's no new buffer memory for BD, drop this frame. + */ +status_t ENET_QOS_GetRxFrame(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + enet_qos_rx_frame_struct_t *rxFrame, + uint8_t channel) +{ + assert(handle != NULL); + assert(channel < handle->rxQueueUse); + + enet_qos_rx_bd_ring_t *rxBdRing = (enet_qos_rx_bd_ring_t *)&handle->rxBdRing[channel]; + enet_qos_rx_bd_struct_t *rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + uint16_t index = rxBdRing->rxGenIdx; + status_t result = kStatus_Success; + uint32_t buff1Addr = 0; + uint32_t buff2Addr = 0; + uint16_t buff1Len = 0; + uint16_t buff2Len = 0; + uint16_t offset = 0; + void *newBuff1 = NULL; + void *newBuff2 = NULL; + bool isDrop = false; + bool isLastBuff = false; + bool tsAvailable = false; + + /* Check the frame status. */ + do + { + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U) + { + result = kStatus_ENET_QOS_RxFrameEmpty; + break; + } + + /* Check timestamp and error. */ + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U) + { + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_RS1V_MASK) != 0U) + { + if ((rxDesc->reserved & ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK) != 0U) + { + /* Context descriptor is expected but might not be yet available. */ + uint8_t retryTimes = 10; + + while (((rxDesc->control & ENET_QOS_RXDESCRIP_WR_OWN_MASK) != 0U) || + ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) == 0U)) + { + /* Timsstamp value is not corrupted. */ + if ((rxDesc->buff1Addr != 0xFFFFFFFFU) && (rxDesc->buff2Addr != 0xFFFFFFFFU)) + { + break; + } + if (retryTimes-- == 0U) + { + break; + } + } + + if (retryTimes != 0U) + { + tsAvailable = true; + } + else + { + result = kStatus_ENET_QOS_RxFrameEmpty; + break; + } + } + } + + /* Get the frame error if there is. */ + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_ERRSUM_MASK) != 0U) + { + ENET_QOS_GetRxFrameErr(rxDesc, &rxFrame->rxFrameError); + result = kStatus_ENET_QOS_RxFrameError; + } + else if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK) == 0U) + { + result = kStatus_ENET_QOS_RxFrameEmpty; + } + else + { + /* Intentional empty */ + } + break; + } + + index = ENET_QOS_IncreaseIndex(index, rxBdRing->rxRingLen); + if (index == rxBdRing->rxGenIdx) + { + result = kStatus_ENET_QOS_RxFrameEmpty; + break; + } + rxDesc = &rxBdRing->rxBdBase[index]; + } while (index != rxBdRing->rxGenIdx); + + /* Drop the error frame and return error. */ + if (result != kStatus_Success) + { + if (result == kStatus_ENET_QOS_RxFrameError) + { + ENET_QOS_DropFrame(base, handle, channel); + } + return result; + } + + /* Get the valid frame */ + index = 0; + do + { + rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + + /* Caculate the buffer and frame length. */ + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_LD_MASK) != 0U) + { + isLastBuff = true; + rxFrame->totLen = (uint16_t)(rxDesc->control & ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK); + + if (rxFrame->totLen - offset > (uint16_t)rxBdRing->rxBuffSizeAlign) + { + buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign; + if (handle->doubleBuffEnable) + { + buff2Len = rxFrame->totLen - offset - (uint16_t)rxBdRing->rxBuffSizeAlign - ENET_QOS_FCS_LEN; + } + } + else + { + buff1Len = rxFrame->totLen - offset - ENET_QOS_FCS_LEN; + } + rxFrame->totLen -= ENET_QOS_FCS_LEN; + } + else + { + if (!handle->doubleBuffEnable) + { + buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign; + offset += buff1Len; + } + else + { + buff1Len = (uint16_t)rxBdRing->rxBuffSizeAlign; + buff2Len = (uint16_t)rxBdRing->rxBuffSizeAlign; + offset += buff1Len + buff2Len; + } + } + + /* Allocate new buffer to replace the buffer taken by application */ + newBuff1 = handle->rxBuffAlloc(base, handle->userData, channel); + if (newBuff1 == NULL) + { + isDrop = true; + } + else if (handle->doubleBuffEnable && (buff2Len != 0U)) + { + newBuff2 = handle->rxBuffAlloc(base, handle->userData, channel); + if (newBuff2 == NULL) + { + handle->rxBuffFree(base, newBuff1, handle->userData, channel); + isDrop = true; + } + } + else + { + /* Intentional empty */ + } + + if (!isDrop) + { + /* Get the frame data information into Rx frame structure. */ + if (!handle->doubleBuffEnable) + { + buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx]; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buff1Addr = MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + if (handle->rxMaintainEnable[channel]) + { + DCACHE_InvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign); + } + rxFrame->rxBuffArray[index].buffer = (void *)(uint32_t *)buff1Addr; + rxFrame->rxBuffArray[index].length = buff1Len; + index++; + } + else + { + buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx]; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buff1Addr = MEMORY_ConvertMemoryMapAddress(buff1Addr, kMEMORY_DMA2Local); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + if (handle->rxMaintainEnable[channel]) + { + DCACHE_InvalidateByRange(buff1Addr, rxBdRing->rxBuffSizeAlign); + } + rxFrame->rxBuffArray[index].buffer = (void *)(uint32_t *)buff1Addr; + rxFrame->rxBuffArray[index].length = buff1Len; + index++; + + /* If there's no data in buffer2, not add it into rxFrame */ + if (buff2Len != 0U) + { + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buff2Addr = MEMORY_ConvertMemoryMapAddress(buff2Addr, kMEMORY_DMA2Local); +#endif /* FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET */ + if (handle->rxMaintainEnable[channel]) + { + DCACHE_InvalidateByRange(buff2Addr, rxBdRing->rxBuffSizeAlign); + } + rxFrame->rxBuffArray[index].buffer = (void *)(uint32_t *)buff2Addr; + rxFrame->rxBuffArray[index].length = buff2Len; + index++; + } + } + + /* Give new buffer from application to BD */ + if (!handle->doubleBuffEnable) + { + if (handle->rxMaintainEnable[channel]) + { + DCACHE_InvalidateByRange((uint32_t)(uint32_t *)newBuff1, rxBdRing->rxBuffSizeAlign); + } +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buff1Addr = MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)newBuff1, kMEMORY_Local2DMA); +#else + buff1Addr = (uint32_t)(uint32_t *)newBuff1; +#endif + handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx] = buff1Addr; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint32_t *)buff1Addr, NULL, handle->rxintEnable, + handle->doubleBuffEnable); + } + else + { + if (handle->rxMaintainEnable[channel]) + { + DCACHE_InvalidateByRange((uint32_t)(uint32_t *)newBuff1, rxBdRing->rxBuffSizeAlign); + } +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buff1Addr = MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)newBuff1, kMEMORY_Local2DMA); +#else + buff1Addr = (uint32_t)(uint32_t *)newBuff1; +#endif + handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx] = buff1Addr; + + if (buff2Len != 0U) + { + if (handle->rxMaintainEnable[channel]) + { + DCACHE_InvalidateByRange((uint32_t)(uint32_t *)newBuff2, rxBdRing->rxBuffSizeAlign); + } +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET + buff2Addr = MEMORY_ConvertMemoryMapAddress((uint32_t)(uint32_t *)newBuff2, kMEMORY_Local2DMA); +#else + buff2Addr = (uint32_t)(uint32_t *)newBuff2; +#endif + handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U] = buff2Addr; + } + else + { + /* If there's no data in buffer2, keep it */ + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; + } + + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint32_t *)buff1Addr, (void *)(uint32_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + } + rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + + /* Update context BD if there is */ + if (isLastBuff && tsAvailable) + { + rxDesc = &rxBdRing->rxBdBase[rxBdRing->rxGenIdx]; + if ((rxDesc->control & ENET_QOS_RXDESCRIP_WR_CTXT_MASK) != 0U) + { + ENET_QOS_StoreRxFrameTime(base, handle, rxDesc, &rxFrame->rxAttribute.timestamp); + rxFrame->rxAttribute.isTsAvail = true; + + if (!handle->doubleBuffEnable) + { + buff1Addr = handle->rxBufferStartAddr[channel][rxBdRing->rxGenIdx]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, NULL, handle->rxintEnable, + handle->doubleBuffEnable); + } + else + { + buff1Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx]; + buff2Addr = handle->rxBufferStartAddr[channel][2U * rxBdRing->rxGenIdx + 1U]; + ENET_QOS_UpdateRxDescriptor(rxDesc, (void *)(uint8_t *)buff1Addr, (void *)(uint8_t *)buff2Addr, + handle->rxintEnable, handle->doubleBuffEnable); + } + rxBdRing->rxGenIdx = ENET_QOS_IncreaseIndex(rxBdRing->rxGenIdx, rxBdRing->rxRingLen); + } + } + /* Always try to start receive, in case it had stopped */ + base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = + (uint32_t)(uint8_t *)&rxBdRing->rxBdBase[rxBdRing->rxRingLen]; + } + else + { + /* Drop frame if there's no new buffer memory */ + + /* Free the incomplete frame buffers. */ + while (index-- != 0U) + { + handle->rxBuffFree(base, &rxFrame->rxBuffArray[index].buffer, handle->userData, channel); + } + + /* Update all left BDs of this frame from current index. */ + ENET_QOS_DropFrame(base, handle, channel); + + result = kStatus_ENET_QOS_RxFrameDrop; + break; + } + } while (!isLastBuff); + + return result; +} + +/*! + * brief Gets the current ENET time from the PTP 1588 timer without IRQ disable. + * + * param base ENET peripheral base address. + * param second The PTP 1588 system timer second. + * param nanosecond The PTP 1588 system timer nanosecond. + * For the unit of the nanosecond is 1ns. so the nanosecond is the real nanosecond. + */ +void ENET_QOS_Ptp1588GetTimerNoIRQDisable(ENET_QOS_Type *base, uint64_t *second, uint32_t *nanosecond) +{ + assert(second != NULL); + assert(nanosecond != NULL); + + uint32_t high_sec[2]; + uint32_t sec[2]; + + /* Get the current PTP time. */ + /* Since register reads are not atomic, we need to check for wraps during the read */ + high_sec[1] = base->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS & ENET_QOS_MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS_TSHWR_MASK; + + do + { + high_sec[0] = high_sec[1]; + + sec[1] = base->MAC_SYSTEM_TIME_SECONDS; + + do + { + sec[0] = sec[1]; + *nanosecond = base->MAC_SYSTEM_TIME_NANOSECONDS & ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_TSSS_MASK; + sec[1] = base->MAC_SYSTEM_TIME_SECONDS; + } while (sec[1] != sec[0]); + + high_sec[1] = + base->MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS & ENET_QOS_MAC_SYSTEM_TIME_HIGHER_WORD_SECONDS_TSHWR_MASK; + } while (high_sec[1] != high_sec[0]); + + *second = ((uint64_t)high_sec[1] << 32U) | sec[1]; + + if ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK) == 0U) + { + /* Binary rollover, the unit of the increment is ~ 0.465 ns. */ + *nanosecond = (*nanosecond * 465U) / 1000U; + } +} + +/*! + * brief Gets the current ENET time from the PTP 1588 timer, get a more accurate value + * with IRQ disabled during get timer. + * + * param base ENET peripheral base address. + * param second The PTP 1588 system timer second. + * param nanosecond The PTP 1588 system timer nanosecond. + * For the unit of the nanosecond is 1ns. so the nanosecond is the real nanosecond. + */ +void ENET_QOS_Ptp1588GetTimer(ENET_QOS_Type *base, uint64_t *second, uint32_t *nanosecond) +{ + uint32_t primask; + + /* Disables the interrupt. */ + primask = DisableGlobalIRQ(); + + ENET_QOS_Ptp1588GetTimerNoIRQDisable(base, second, nanosecond); + + /* Enables the interrupt. */ + EnableGlobalIRQ(primask); +} + +/*! + * brief Coreect the ENET PTP 1588 timer in coarse method. + * + * param base ENET peripheral base address. + * param operation The system time operation, refer to "enet_qos_systime_op" + * param second The correction second. + * param nanosecond The correction nanosecond. + */ +status_t ENET_QOS_Ptp1588CorrectTimerInCoarse(ENET_QOS_Type *base, + enet_qos_systime_op operation, + uint32_t second, + uint32_t nanosecond) +{ + uint32_t corrSecond = second; + uint32_t corrNanosecond; + status_t result = kStatus_Success; + + /* Set the system timer. */ + if ((base->MAC_TIMESTAMP_CONTROL & ENET_QOS_MAC_TIMESTAMP_CONTROL_TSCTRLSSR_MASK) != 0U) + { + if (operation == kENET_QOS_SystimeSubtract) + { + /* Set with the complement of the sub-second. */ + corrSecond = ENET_QOS_MAC_SYSTEM_TIME_SECONDS_UPDATE_TSS_MASK - (second - 1U); + corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_ADDSUB_MASK | + ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(ENET_QOS_NANOSECS_ONESECOND - nanosecond); + } + else + { + corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(nanosecond); + } + } + else + { + nanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS_MASK / ENET_QOS_NANOSECS_ONESECOND * nanosecond; + if (operation == kENET_QOS_SystimeSubtract) + { + /* Set with the complement of the sub-second. */ + corrSecond = ENET_QOS_MAC_SYSTEM_TIME_SECONDS_UPDATE_TSS_MASK - (second - 1U); + corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_ADDSUB_MASK | + ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS( + ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS_MASK + 1U - nanosecond); + } + else + { + corrNanosecond = ENET_QOS_MAC_SYSTEM_TIME_NANOSECONDS_UPDATE_TSSS(nanosecond); + } + } + + base->MAC_SYSTEM_TIME_SECONDS_UPDATE = corrSecond; + base->MAC_SYSTEM_TIME_NANOSECONDS_UPDATE = corrNanosecond; + + /* Update the timer. */ + base->MAC_TIMESTAMP_CONTROL |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSUPDT_MASK; + + /* Wait for update finish */ + result = ENET_QOS_PollStatusFlag(&(base->MAC_TIMESTAMP_CONTROL), ENET_QOS_MAC_TIMESTAMP_CONTROL_TSUPDT_MASK, 0U); + + return result; +} + +/*! + * brief Correct the ENET PTP 1588 timer in fine method. + * + * + * param base ENET peripheral base address. + * param addend The addend value to be set in the fine method + * note Should take refer to the chapter "System time correction" and + * see the description for the "fine correction method". + */ +status_t ENET_QOS_Ptp1588CorrectTimerInFine(ENET_QOS_Type *base, uint32_t addend) +{ + status_t result = kStatus_Success; + + base->MAC_TIMESTAMP_ADDEND = addend; + base->MAC_TIMESTAMP_CONTROL |= ENET_QOS_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK; + + result = ENET_QOS_PollStatusFlag(&(base->MAC_TIMESTAMP_CONTROL), ENET_QOS_MAC_TIMESTAMP_CONTROL_TSADDREG_MASK, 0U); + + return result; +} + +/*! + * @brief Sets the ENET OQS PTP 1588 PPS target time registers. + * + * param base ENET QOS peripheral base address. + * param instance The ENET QOS PTP PPS instance. + * param seconds The target seconds. + * param nanoseconds The target nanoseconds. + */ +status_t ENET_QOS_Ptp1588PpsSetTrgtTime(ENET_QOS_Type *base, + enet_qos_ptp_pps_instance_t instance, + uint32_t seconds, + uint32_t nanoseconds) +{ + uint32_t *mac_pps_trgt_ns; + uint32_t *mac_pps_trgt_s; + + mac_pps_trgt_ns = (uint32_t *)((uint32_t)&base->MAC_PPS0_TARGET_TIME_NANOSECONDS + 0x10U * (uint32_t)instance); + mac_pps_trgt_s = (uint32_t *)((uint32_t)&base->MAC_PPS0_TARGET_TIME_SECONDS + 0x10U * (uint32_t)instance); + + if ((*mac_pps_trgt_ns & ENET_QOS_MAC_PPS0_TARGET_TIME_NANOSECONDS_TRGTBUSY0_MASK) != 0U) + { + return kStatus_ENET_QOS_TrgtBusy; + } + + *mac_pps_trgt_ns = ENET_QOS_MAC_PPS0_TARGET_TIME_NANOSECONDS_TTSL0(nanoseconds); + *mac_pps_trgt_s = ENET_QOS_MAC_PPS0_TARGET_TIME_SECONDS_TSTRH0(seconds); + + return kStatus_Success; +} + +static status_t ENET_QOS_EstReadWriteWord( + ENET_QOS_Type *base, uint32_t addr, uint32_t *data, uint8_t gcrr, uint8_t read, uint8_t dbgm) +{ + uint32_t ctrl; + int retry = 10; + + ctrl = ENET_QOS_MTL_EST_GCL_CONTROL_ADDR(addr) | ENET_QOS_MTL_EST_GCL_CONTROL_SRWO(1) | + ENET_QOS_MTL_EST_GCL_CONTROL_DBGM(dbgm) | ENET_QOS_MTL_EST_GCL_CONTROL_GCRR(gcrr); + + if (read != 0U) + { + ctrl |= ENET_QOS_MTL_EST_GCL_CONTROL_R1W0(1); + } + else + { + base->MTL_EST_GCL_DATA = *data; + } + + base->MTL_EST_GCL_CONTROL = ctrl; + + while ((base->MTL_EST_GCL_CONTROL & ENET_QOS_MTL_EST_GCL_CONTROL_SRWO_MASK) != 0U) + { + if (retry-- < 0) + { + return kStatus_Timeout; + } + SDK_DelayAtLeastUs(1, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY); + } + + if (read != 0U) + { + *data = base->MTL_EST_GCL_DATA; + } + + if ((base->MTL_EST_GCL_CONTROL & ENET_QOS_MTL_EST_GCL_CONTROL_ERR0_MASK) != 0U) + { + return kStatus_ENET_QOS_Est_SwListWriteAbort; + } + + return kStatus_Success; +} + +static status_t ENET_QOS_EstProgramWord(ENET_QOS_Type *base, uint32_t addr, uint32_t *data, uint8_t gcrr) +{ + return ENET_QOS_EstReadWriteWord(base, addr, data, gcrr, 0, 0); +} + +static status_t ENET_QOS_EstReadWord(ENET_QOS_Type *base, uint32_t addr, uint32_t *data, uint8_t gcrr, uint8_t dbgm) +{ + return ENET_QOS_EstReadWriteWord(base, addr, data, gcrr, 1, dbgm); +} + +/*! + * @brief Program Gate Control List. + * + * This function is used to program the Enhanced Scheduled Transmisson. (IEEE802.1Qbv) + * + * @param base ENET peripheral base address.. + * @param gcl Pointer to the Gate Control List structure. + * @param ptpClk_Hz frequency of the PTP clock. + */ +status_t ENET_QOS_EstProgramGcl(ENET_QOS_Type *base, enet_qos_est_gcl_t *gcl, uint32_t ptpClk_Hz) +{ + assert(gcl != NULL); + uint32_t i, control, data; + enet_qos_est_gate_op_t *gateOp; + status_t rc; + +#define EST_MAX_INTERVAL ((1UL << ENET_QOS_EST_WID) - 1U) +#define EST_MAX_GATE ((1UL << (32U - ENET_QOS_EST_WID)) - 1U) + + if (!gcl->enable) + { + goto exit; + } + + /* Sanity checks */ + if (gcl->numEntries > ENET_QOS_EST_DEP) + { + return kStatus_ENET_QOS_Est_InvalidParameter; + } + + if (gcl->opList == NULL) + { + return kStatus_ENET_QOS_Est_InvalidParameter; + } + + gateOp = gcl->opList; + + for (i = 0; i < gcl->numEntries; i++) + { + if (gateOp->interval > EST_MAX_INTERVAL) + { + return kStatus_ENET_QOS_Est_InvalidParameter; + } + if (gateOp->gate > EST_MAX_GATE) + { + return kStatus_ENET_QOS_Est_InvalidParameter; + } + gateOp++; + } + + /* Check if sw list is busy */ + if ((base->MTL_EST_CONTROL & ENET_QOS_MTL_EST_CONTROL_SSWL_MASK) != 0U) + { + return kStatus_ENET_QOS_Est_SwListBusy; + } + + gateOp = gcl->opList; + + for (i = 0; i < gcl->numEntries; i++) + { + data = gateOp->interval | (gateOp->gate << ENET_QOS_EST_WID); + rc = ENET_QOS_EstProgramWord(base, i, &data, 0); + if (rc != kStatus_Success) + { + return rc; + } + + gateOp++; + } + + /* BTR High */ + data = (uint32_t)(gcl->baseTime >> 32U); + rc = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_btr_high, &data, 1U); + if (rc != kStatus_Success) + { + return rc; + } + + /* BTR Low */ + data = (uint32_t)gcl->baseTime; + rc = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_btr_low, &data, 1); + if (rc != kStatus_Success) + { + return rc; + } + + /* CTR High */ + data = (uint32_t)(gcl->cycleTime >> 32U); + rc = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_ctr_high, &data, 1); + if (rc != kStatus_Success) + { + return rc; + } + + /* CTR Low */ + data = (uint32_t)gcl->cycleTime; + rc = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_ctr_low, &data, 1); + if (rc != kStatus_Success) + { + return rc; + } + + /* TER */ + data = gcl->extTime; + rc = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_ter, &data, 1); + if (rc != kStatus_Success) + { + return rc; + } + + /* LLR */ + data = gcl->numEntries; + rc = ENET_QOS_EstProgramWord(base, (uint32_t)kENET_QOS_Ets_llr, &data, 1); + if (rc != kStatus_Success) + { + return rc; + } + +exit: + control = base->MTL_EST_CONTROL; + + if (gcl->enable) + { + control &= ~ENET_QOS_MTL_EST_CONTROL_PTOV_MASK; + control |= ENET_QOS_MTL_EST_CONTROL_SSWL_MASK | ENET_QOS_MTL_EST_CONTROL_EEST_MASK | + ENET_QOS_MTL_EST_CONTROL_PTOV((1000000000U / ptpClk_Hz) * 6U); + } + else + { + control &= ~ENET_QOS_MTL_EST_CONTROL_EEST_MASK; + } + + base->MTL_EST_CONTROL = control; + + return kStatus_Success; +} + +/*! + * @brief Read Gate Control List. + * + * This function is used to read the Enhanced Scheduled Transmisson list. (IEEE802.1Qbv) + * + * @param base ENET peripheral base address.. + * @param gcl Pointer to the Gate Control List structure. + * @param listLen length of the provided opList array in gcl structure. + * @param hwList Boolean if True read HW list, false read SW list. + */ +status_t ENET_QOS_EstReadGcl(ENET_QOS_Type *base, enet_qos_est_gcl_t *gcl, uint32_t listLen, bool hwList) +{ + assert(gcl != NULL); + assert(gcl->opList != NULL); + uint8_t dbgm = 0; + uint32_t data, i; + enet_qos_est_gate_op_t *gateOp; + status_t rc; + + if (hwList == true) + { + dbgm = 1; + } + + /* LLR */ + rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_llr, &data, 1, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gcl->numEntries = data; + + if (gcl->numEntries > listLen) + { + return kStatus_ENET_QOS_Est_InvalidParameter; + } + + /* BTR High */ + rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_btr_high, &data, 1, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gcl->baseTime = (uint64_t)data << 32U; + + /* BTR Low */ + rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_btr_low, &data, 1, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gcl->baseTime |= data; + + /* CTR High */ + rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_ctr_high, &data, 1, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gcl->cycleTime = (uint64_t)data << 32U; + + /* CTR Low */ + rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_ctr_low, &data, 1, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gcl->cycleTime |= data; + + /* TER */ + rc = ENET_QOS_EstReadWord(base, (uint32_t)kENET_QOS_Ets_ter, &data, 1, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gcl->extTime = data; + + gateOp = gcl->opList; + + for (i = 0; i < gcl->numEntries; i++) + { + rc = ENET_QOS_EstReadWord(base, i, &data, 0, dbgm); + if (rc != kStatus_Success) + { + return rc; + } + + gateOp->interval = data & (EST_MAX_INTERVAL); + gateOp->gate = data >> ENET_QOS_EST_WID; + gateOp++; + } + + return kStatus_Success; +} + +/*! + * brief Read flexible rx parser configuration at specified index. + * + * This function is used to read flexible rx parser configuration at specified index. + * + * param base ENET peripheral base address.. + * param rxpConfig The rx parser configuration pointer. + * param entryIndex The rx parser entry index to read, start from 0. + * retval kStatus_Success Configure rx parser success. + * retval kStatus_ENET_QOS_Timeout Poll status flag timeout. + */ +status_t ENET_QOS_ReadRxParser(ENET_QOS_Type *base, enet_qos_rxp_config_t *rxpConfig, uint16_t entryIndex) +{ + assert(rxpConfig != NULL); + assert(entryIndex < ENET_QOS_RXP_ENTRY_COUNT); + + uint32_t *dataPtr; + uint8_t entrySize = sizeof(enet_qos_rxp_config_t) / sizeof(uint32_t); + uint32_t value = 0U; + status_t result = kStatus_Success; + + /* Wait hardware not busy */ + result = ENET_QOS_PollStatusFlag(&(base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS), + ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U); + if (kStatus_Success != result) + { + return result; + } + + for (uint8_t i = 0; i < entrySize; i++) + { + /* Read address. */ + value = ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_ADDR((uint32_t)entrySize * entryIndex + i); + + /* Issue read command. */ + value &= ~ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_WRRDN_MASK; + base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value; + + /* Start Read */ + value |= ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK; + base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value; + + /* Wait hardware not busy */ + result = ENET_QOS_PollStatusFlag(&base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS, + ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U); + if (kStatus_Success != result) + { + return result; + } + + dataPtr = (uint32_t *)(void *)&rxpConfig[entryIndex]; + dataPtr = &dataPtr[i]; + /* Read data */ + *dataPtr = base->MTL_RXP_INDIRECT_ACC_DATA; + } + + return result; +} + +/*! + * brief Configure flexible rx parser. + * + * This function is used to configure the flexible rx parser table. + * + * param base ENET peripheral base address.. + * param rxpConfig The rx parser configuration pointer. + * param entryCount The rx parser entry count. + * retval kStatus_Success Configure rx parser success. + * retval kStatus_ENET_QOS_Timeout Poll status flag timeout. + */ +status_t ENET_QOS_ConfigureRxParser(ENET_QOS_Type *base, enet_qos_rxp_config_t *rxpConfig, uint16_t entryCount) +{ + assert(rxpConfig != NULL); + assert(entryCount <= ENET_QOS_RXP_ENTRY_COUNT); + + uint32_t *dataPtr; + uint32_t entrySize = sizeof(enet_qos_rxp_config_t) / sizeof(uint32_t); + uint32_t value = 0U; + status_t result = kStatus_Success; + bool enableRx = false; + + /* Disable the MAC rx. */ + if (0U != (base->MAC_CONFIGURATION & ENET_QOS_MAC_CONFIGURATION_RE_MASK)) + { + base->MAC_CONFIGURATION &= ~ENET_QOS_MAC_CONFIGURATION_RE_MASK; + enableRx = true; + } + + /* Disable frame parser. */ + result = ENET_QOS_EnableRxParser(base, false); + + if (kStatus_Success != result) + { + return result; + } + + for (uint8_t count = 0; count < entryCount; count++) + { + for (uint8_t i = 0; i < entrySize; i++) + { + /* Wait hardware not busy */ + result = ENET_QOS_PollStatusFlag(&base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS, + ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U); + if (kStatus_Success != result) + { + return result; + } + + dataPtr = (uint32_t *)(void *)&rxpConfig[count]; + dataPtr = &dataPtr[i]; + + /* Write data before issue write command */ + base->MTL_RXP_INDIRECT_ACC_DATA = *dataPtr; + + /* Write address and issue write command */ + value = ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_ADDR(entrySize * count + i); + // base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value; + + value |= ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_WRRDN_MASK; + base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value; + + /* Start write */ + value |= ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK; + base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS = value; + } + } + + /* Wait hardware not busy */ + result = ENET_QOS_PollStatusFlag(&(base->MTL_RXP_INDIRECT_ACC_CONTROL_STATUS), + ENET_QOS_MTL_RXP_INDIRECT_ACC_CONTROL_STATUS_STARTBUSY_MASK, 0U); + if (kStatus_Success != result) + { + return result; + } + + /* Program NVE and NPE. */ + value = base->MTL_RXP_CONTROL_STATUS; + value &= ~(ENET_QOS_MTL_RXP_CONTROL_STATUS_NVE_MASK | ENET_QOS_MTL_RXP_CONTROL_STATUS_NPE_MASK); + + value |= ENET_QOS_MTL_RXP_CONTROL_STATUS_NPE((uint32_t)entryCount - 1U); + if (entryCount < 3U) + { + value |= ENET_QOS_MTL_RXP_CONTROL_STATUS_NVE(2U); + } + else + { + value |= ENET_QOS_MTL_RXP_CONTROL_STATUS_NVE((uint32_t)entryCount - 1U); + } + + base->MTL_RXP_CONTROL_STATUS = value; + + /* Enable frame parser. */ + result = ENET_QOS_EnableRxParser(base, true); + + /* Enable Receive */ + if (enableRx) + { + base->MAC_CONFIGURATION |= ENET_QOS_MAC_CONFIGURATION_RE_MASK; + } + + return result; +} + +/*! + * brief Gets statistical data in transfer. + * + * param base ENET_QOS peripheral base address. + * param statistics The statistics structure pointer. + */ +void ENET_QOS_GetStatistics(ENET_QOS_Type *base, enet_qos_transfer_stats_t *statistics) +{ + /* Rx statistics */ + statistics->statsRxFrameCount = base->MAC_RX_PACKETS_COUNT_GOOD_BAD; + statistics->statsRxCrcErr = base->MAC_RX_CRC_ERROR_PACKETS; + statistics->statsRxAlignErr = base->MAC_RX_ALIGNMENT_ERROR_PACKETS; + statistics->statsRxLengthErr = base->MAC_RX_LENGTH_ERROR_PACKETS; + statistics->statsRxFifoOverflowErr = base->MAC_RX_FIFO_OVERFLOW_PACKETS; + + /* Tx statistics */ + statistics->statsTxFrameCount = base->MAC_TX_PACKET_COUNT_GOOD_BAD; + statistics->statsTxFifoUnderRunErr = base->MAC_TX_UNDERFLOW_ERROR_PACKETS; +} + +/*! + * brief The ENET IRQ handler. + * + * param base ENET peripheral base address. + * param handle The ENET handler pointer. + */ +void ENET_QOS_CommonIRQHandler(ENET_QOS_Type *base, enet_qos_handle_t *handle) +{ + /* Check for the interrupt source type. */ + /* DMA CHANNEL 0. */ + if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC0IS_MASK) != 0U) + { + uint32_t flag = base->DMA_CH[0].DMA_CHX_STAT; + if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U) + { + base->DMA_CH[0].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + if (handle->callback != NULL) + { + handle->callback(base, handle, kENET_QOS_RxIntEvent, 0, handle->userData); + } + } + if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U) + { + base->DMA_CH[0].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + ENET_QOS_ReclaimTxDescriptor(base, handle, 0); + } + } + + /* DMA CHANNEL 1. */ + if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC1IS_MASK) != 0U) + { + uint32_t flag = base->DMA_CH[1].DMA_CHX_STAT; + if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U) + { + base->DMA_CH[1].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + if (handle->callback != NULL) + { + handle->callback(base, handle, kENET_QOS_RxIntEvent, 1, handle->userData); + } + } + if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U) + { + base->DMA_CH[1].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + ENET_QOS_ReclaimTxDescriptor(base, handle, 1); + } + } + + /* DMA CHANNEL 2. */ + if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC2IS_MASK) != 0U) + { + uint32_t flag = base->DMA_CH[2].DMA_CHX_STAT; + if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U) + { + base->DMA_CH[2].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + if (handle->callback != NULL) + { + handle->callback(base, handle, kENET_QOS_RxIntEvent, 2, handle->userData); + } + } + if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U) + { + base->DMA_CH[2].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + ENET_QOS_ReclaimTxDescriptor(base, handle, 2); + } + } + + /* DMA CHANNEL 3. */ + if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_DC3IS_MASK) != 0U) + { + uint32_t flag = base->DMA_CH[3].DMA_CHX_STAT; + if ((flag & ENET_QOS_DMA_CHX_STAT_RI_MASK) != 0U) + { + base->DMA_CH[3].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_RI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + if (handle->callback != NULL) + { + handle->callback(base, handle, kENET_QOS_RxIntEvent, 3, handle->userData); + } + } + if ((flag & ENET_QOS_DMA_CHX_STAT_TI_MASK) != 0U) + { + base->DMA_CH[3].DMA_CHX_STAT = ENET_QOS_DMA_CHX_STAT_TI_MASK | ENET_QOS_DMA_CHX_STAT_NIS_MASK; + ENET_QOS_ReclaimTxDescriptor(base, handle, 3); + } + } + + /* MAC TIMESTAMP. */ + if ((base->DMA_INTERRUPT_STATUS & ENET_QOS_DMA_INTERRUPT_STATUS_MACIS_MASK) != 0U) + { + if ((base->MAC_INTERRUPT_STATUS & ENET_QOS_MAC_INTERRUPT_STATUS_TSIS_MASK) != 0U) + { + if (handle->callback != NULL) + { + handle->callback(base, handle, kENET_QOS_TimeStampIntEvent, 0, handle->userData); + } + } + } + SDK_ISR_EXIT_BARRIER; +} + +#if defined(ENET_QOS) +void ENET_QOS_DriverIRQHandler(void); +void ENET_QOS_DriverIRQHandler(void) +{ + s_enetqosIsr(ENET_QOS, s_ENETHandle[0]); +} +#endif + +#if defined(CONNECTIVITY__ENET_QOS) +void CONNECTIVITY_EQOS_INT_DriverIRQHandler(void); +void CONNECTIVITY_EQOS_INT_DriverIRQHandler(void) +{ + s_enetqosIsr(CONNECTIVITY__ENET_QOS, s_ENETHandle[0]); +} +#endif diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/Makefile new file mode 100755 index 000000000..bef95c0eb --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := +SRC_DIR := enet enet_qos +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/Makefile new file mode 100755 index 000000000..cd39a7a18 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_enet_mdio.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/fsl_enet_mdio.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/fsl_enet_mdio.c new file mode 100644 index 000000000..3e99a8891 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/fsl_enet_mdio.c @@ -0,0 +1,133 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_enet_mdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void ENET_MDIO_Init(mdio_handle_t *handle); +static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data); +static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +const mdio_operations_t enet_ops = {.mdioInit = ENET_MDIO_Init, + .mdioWrite = ENET_MDIO_Write, + .mdioRead = ENET_MDIO_Read, + .mdioWriteExt = NULL, + .mdioReadExt = NULL}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void ENET_MDIO_Init(mdio_handle_t *handle) +{ + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_Type *base = (ENET_Type *)resource->base; + uint32_t instance = ENET_GetInstance(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Set SMI first. */ + (void)CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + ENET_SetSMI(base, resource->csrClock_Hz, false); +} + +static status_t ENET_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) +{ + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_Type *base = (ENET_Type *)resource->base; + status_t result = kStatus_Success; +#ifdef MDIO_TIMEOUT_COUNT + uint32_t counter; +#endif + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI write command. */ + ENET_StartSMIWrite(base, phyAddr, devAddr, kENET_MiiWriteValidFrame, data); + + /* Wait for SMI complete. */ +#ifdef MDIO_TIMEOUT_COUNT + for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--) + { + if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) + { + break; + } + } + /* Check for timeout. */ + if (0U == counter) + { + result = kStatus_PHY_SMIVisitTimeout; + } +#else + while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) + { + } +#endif + + /* Clear SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return result; +} + +static status_t ENET_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) +{ + assert(dataPtr); + + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_Type *base = (ENET_Type *)resource->base; +#ifdef MDIO_TIMEOUT_COUNT + uint32_t counter; +#endif + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI read command operation. */ + ENET_StartSMIRead(base, phyAddr, devAddr, kENET_MiiReadValidFrame); + + /* Wait for SMI complete. */ +#ifdef MDIO_TIMEOUT_COUNT + for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--) + { + if (ENET_EIR_MII_MASK == (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) + { + break; + } + } + /* Check for timeout. */ + if (0U == counter) + { + return kStatus_PHY_SMIVisitTimeout; + } +#else + while (ENET_EIR_MII_MASK != (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK)) + { + } +#endif + + /* Get data from SMI register. */ + *dataPtr = ENET_ReadSMIData(base); + + /* Clear SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return kStatus_Success; +} diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/fsl_enet_mdio.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/fsl_enet_mdio.h new file mode 100644 index 000000000..48ae52d9a --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet/fsl_enet_mdio.h @@ -0,0 +1,21 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_ENET_MDIO_H_ +#define _FSL_ENET_MDIO_H_ + +#include "fsl_enet.h" +#include "fsl_mdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief ENET MDIO operations structure. */ +extern const mdio_operations_t enet_ops; + +#endif diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/Makefile new file mode 100755 index 000000000..aa16fe478 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_enet_qos_mdio.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/fsl_enet_qos_mdio.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/fsl_enet_qos_mdio.c new file mode 100644 index 000000000..aabb4377d --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/fsl_enet_qos_mdio.c @@ -0,0 +1,113 @@ +/* + * Copyright 2020-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_enet_qos_mdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +static void ENET_QOS_MDIO_Init(mdio_handle_t *handle); + +static status_t ENET_QOS_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data); + +static status_t ENET_QOS_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +const mdio_operations_t enet_qos_ops = {.mdioInit = ENET_QOS_MDIO_Init, + .mdioWrite = ENET_QOS_MDIO_Write, + .mdioRead = ENET_QOS_MDIO_Read, + .mdioWriteExt = NULL, + .mdioReadExt = NULL}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +static void ENET_QOS_MDIO_Init(mdio_handle_t *handle) +{ + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_QOS_Type *base = (ENET_QOS_Type *)resource->base; + uint32_t instance = ENET_QOS_GetInstance(base); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Set SMI first. */ + CLOCK_EnableClock(s_enetqosClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + ENET_QOS_SetSMI(base, resource->csrClock_Hz); +} + +static status_t ENET_QOS_MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) +{ + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_QOS_Type *base = (ENET_QOS_Type *)resource->base; + status_t result = kStatus_Success; +#ifdef MDIO_TIMEOUT_COUNT + uint32_t counter; +#endif + + ENET_QOS_StartSMIWrite(base, phyAddr, devAddr, data); + +#ifdef MDIO_TIMEOUT_COUNT + for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--) + { + if (!ENET_QOS_IsSMIBusy(base)) + { + break; + } + } + /* Check for timeout. */ + if (0U == counter) + { + result = kStatus_PHY_SMIVisitTimeout; + } +#else + while (ENET_QOS_IsSMIBusy(base)) + { + } +#endif + return result; +} + +static status_t ENET_QOS_MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) +{ + mdio_resource_t *resource = (mdio_resource_t *)&handle->resource; + ENET_QOS_Type *base = (ENET_QOS_Type *)resource->base; + status_t result = kStatus_Success; +#ifdef MDIO_TIMEOUT_COUNT + uint32_t counter; +#endif + + ENET_QOS_StartSMIRead(base, phyAddr, devAddr); +#ifdef MDIO_TIMEOUT_COUNT + for (counter = MDIO_TIMEOUT_COUNT; counter > 0U; counter--) + { + if (!ENET_QOS_IsSMIBusy(base)) + { + break; + } + } + /* Check for timeout. */ + if (0U == counter) + { + result = kStatus_PHY_SMIVisitTimeout; + } +#else + while (ENET_QOS_IsSMIBusy(base)) + { + } +#endif + *dataPtr = ENET_QOS_ReadSMIData(base); + return result; +} diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/fsl_enet_qos_mdio.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/fsl_enet_qos_mdio.h new file mode 100644 index 000000000..0b7f8bf91 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/mdio/enet_qos/fsl_enet_qos_mdio.h @@ -0,0 +1,21 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _FSL_ENET_QOS_MDIO_H_ +#define _FSL_ENET_QOS_MDIO_H_ + +#include "fsl_enet_qos.h" +#include "fsl_mdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief ENET_QOS MDIO operations structure. */ +extern const mdio_operations_t enet_qos_ops; + +#endif diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/Makefile new file mode 100755 index 000000000..4eaeca6a4 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := +SRC_DIR := ksz8081 ksz9131rnx +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/Makefile new file mode 100755 index 000000000..54154c103 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/Makefile @@ -0,0 +1,2 @@ +SRC_FILES := fsl_phyksz8081.c +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/fsl_phyksz8081.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/fsl_phyksz8081.c new file mode 100644 index 000000000..c9c5dd2dc --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/fsl_phyksz8081.c @@ -0,0 +1,344 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_phyksz8081.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +/* define by AIIT lab */ +#define FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE + +/*! @brief Defines the PHY KSZ8081 vendor defined registers. */ +#define PHY_CONTROL1_REG 0x1EU /*!< The PHY control one register. */ +#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */ + +/*! @brief Defines the PHY KSZ8081 ID number. */ +#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1 */ + +/*! @brief Defines the mask flag of operation mode in control registers */ +#define PHY_CTL2_REMOTELOOP_MASK 0x0004U /*!< The PHY remote loopback mask. */ +#define PHY_CTL2_REFCLK_SELECT_MASK 0x0080U /*!< The PHY RMII reference clock select. */ +#define PHY_CTL1_10HALFDUPLEX_MASK 0x0001U /*!< The PHY 10M half duplex mask. */ +#define PHY_CTL1_100HALFDUPLEX_MASK 0x0002U /*!< The PHY 100M half duplex mask. */ +#define PHY_CTL1_10FULLDUPLEX_MASK 0x0005U /*!< The PHY 10M full duplex mask. */ +#define PHY_CTL1_100FULLDUPLEX_MASK 0x0006U /*!< The PHY 100M full duplex mask. */ +#define PHY_CTL1_SPEEDUPLX_MASK 0x0007U /*!< The PHY speed and duplex mask. */ +#define PHY_CTL1_ENERGYDETECT_MASK 0x10U /*!< The PHY signal present on rx differential pair. */ +#define PHY_CTL1_LINKUP_MASK 0x100U /*!< The PHY link up. */ +#define PHY_LINK_READY_MASK (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK) + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +const phy_operations_t phyksz8081_ops = {.phyInit = PHY_KSZ8081_Init, + .phyWrite = PHY_KSZ8081_Write, + .phyRead = PHY_KSZ8081_Read, + .getAutoNegoStatus = PHY_KSZ8081_GetAutoNegotiationStatus, + .getLinkStatus = PHY_KSZ8081_GetLinkStatus, + .getLinkSpeedDuplex = PHY_KSZ8081_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_KSZ8081_SetLinkSpeedDuplex, + .enableLoopback = PHY_KSZ8081_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config) +{ + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result = kStatus_Success; + uint32_t regValue = 0; + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) + { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) + { + return kStatus_Fail; + } + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) + { +#if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE) + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, ®Value); + if (result != kStatus_Success) + { + return result; + } + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, (regValue | PHY_CTL2_REFCLK_SELECT_MASK)); + if (result != kStatus_Success) + { + return result; + } +#endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */ + + if (config->autoNeg) + { + /* Set the auto-negotiation then start it. */ + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | PHY_IEEE802_3_SELECTOR_MASK)); + if (result == kStatus_Success) + { + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + else + { + /* This PHY only supports 10/100M speed. */ + assert(config->speed <= kPHY_Speed100M); + + /* Disable isolate mode */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result != kStatus_Success) + { + return result; + } + regValue &= ~PHY_BCTL_ISOLATE_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) + { + return result; + } + + /* Disable the auto-negotiation and set user-defined speed/duplex configuration. */ + result = PHY_KSZ8081_SetLinkSpeedDuplex(handle, config->speed, config->duplex); + } + } + return result; +} + +status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) +{ + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) +{ + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) +{ + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) + { + + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) + { + *status = true; + } + } + return result; +} + +status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status) +{ + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the basic status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) + { + + if ((PHY_BSTATUS_LINKSTATUS_MASK & regValue) != 0U) + { + /* Link up. */ + *status = true; + } + else + { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) +{ + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + uint32_t flag; + + /* Read the control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL1_REG, ®Value); + if (result == kStatus_Success) + { + if (speed != NULL) + { + flag = regValue & PHY_CTL1_SPEEDUPLX_MASK; + if ((PHY_CTL1_100HALFDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) + { + *speed = kPHY_Speed100M; + } + else + { + *speed = kPHY_Speed10M; + } + } + + if (duplex != NULL) + { + flag = regValue & PHY_CTL1_SPEEDUPLX_MASK; + if ((PHY_CTL1_10FULLDUPLEX_MASK == flag) || (PHY_CTL1_100FULLDUPLEX_MASK == flag)) + { + *duplex = kPHY_FullDuplex; + } + else + { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) +{ + /* This PHY only supports 10/100M speed. */ + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) + { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed100M) + { + regValue |= PHY_BCTL_SPEED0_MASK; + } + else + { + regValue &= ~PHY_BCTL_SPEED0_MASK; + } + if (duplex == kPHY_FullDuplex) + { + regValue |= PHY_BCTL_DUPLEX_MASK; + } + else + { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} + +status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) +{ + /* This PHY only supports local/remote loopback and 10/100M speed. */ + assert(mode <= kPHY_RemoteLoop); + assert(speed <= kPHY_Speed100M); + + status_t result; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) + { + if (mode == kPHY_LocalLoop) + { + if (speed == kPHY_Speed100M) + { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + else + { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + else + { + /* Remote loopback only supports 100M full-duplex. */ + assert(speed == kPHY_Speed100M); + + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + if (result != kStatus_Success) + { + return result; + } + /* Set the remote loopback bit. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, ®Value); + if (result == kStatus_Success) + { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, + (regValue | PHY_CTL2_REMOTELOOP_MASK)); + } + } + } + else + { + /* Disable the loop mode. */ + if (mode == kPHY_LocalLoop) + { + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) + { + regValue &= ~PHY_BCTL_LOOP_MASK; + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + else + { + /* First read the current status in control one register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, ®Value); + if (result == kStatus_Success) + { + return MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_CONTROL2_REG, + (regValue & ~PHY_CTL2_REMOTELOOP_MASK)); + } + } + } + return result; +} diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/fsl_phyksz8081.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/fsl_phyksz8081.h new file mode 100644 index 000000000..ff9e7d0d5 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz8081/fsl_phyksz8081.h @@ -0,0 +1,163 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/***************************************************************************** + * PHY KSZ8081 driver change log + *****************************************************************************/ + +/*! +@page driver_log Driver Change Log + +@section phyksz8081 PHYKSZ8081 + The current PHYKSZ8081 driver version is 2.0.0. + + - 2.0.0 + - Initial version. +*/ + +#ifndef _FSL_PHYKSZ8081_H_ +#define _FSL_PHYKSZ8081_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phyksz8081_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ8081_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHYKSZ8081_H_ */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/Kconfig b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/Makefile new file mode 100755 index 000000000..c4d759d96 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := fsl_phyksz9131rnx.c + +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/fsl_phyksz9131rnx.c b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/fsl_phyksz9131rnx.c new file mode 100644 index 000000000..2b5143f24 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/fsl_phyksz9131rnx.c @@ -0,0 +1,302 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_phyksz9131rnx.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the PHY RTL8211F vendor defined registers. */ +#define PHY_SPECIFIC_STATUS_REG 0x01U /*!< The PHY specific status register. */ +#define PHY_PAGE_SELECT_REG 0x1FU /*!< The PHY page select register. */ + +/*! @brief Defines the PHY RTL8211F ID number. */ +#define PHY_CONTROL_ID1 0x0022U /*!< The PHY ID1 . */ + +/*! @brief Defines the mask flag in specific status register. */ +#define PHY_SSTATUS_LINKSTATUS_MASK 0x04U /*!< The PHY link status mask. */ +#define PHY_SSTATUS_LINKSPEED_MASK 0x30U /*!< The PHY link speed mask. */ +#define PHY_SSTATUS_LINKDUPLEX_MASK 0x08U /*!< The PHY link duplex mask. */ +#define PHY_SSTATUS_LINKSPEED_SHIFT 4U /*!< The link speed shift */ + +/*! @brief Defines the PHY RTL8211F extra page and the registers in specified page. */ +#define PHY_PAGE_RGMII_TXRX_DELAY_ADDR 0xD08U /*!< The register page including RGMII TX/RX delay setting. */ +#define PHY_RGMII_TX_DELAY_REG 0x11U /*!< The RGMII TXC delay register. */ +#define PHY_RGMII_RX_DELAY_REG 0x15U /*!< The RGMII RXC delay register. */ +#define PHY_RGMII_TX_DELAY_MASK 0x100U /*!< The RGMII TXC delay mask. */ +#define PHY_RGMII_RX_DELAY_MASK 0x8U /*!< The RGMII RXC delay mask. */ + +/*! @brief MDIO MMD Devices .*/ +#define PHY_MDIO_MMD_PCS 3U +#define PHY_MDIO_MMD_AN 7U + +/*! @brief MDIO MMD Physical Coding layer device registers .*/ +#define PHY_MDIO_PCS_EEE_CAP 0x14U /* EEE capability */ + +/*! @brief MDIO MMD AutoNegotiation device registers .*/ +#define PHY_MDIO_AN_EEE_ADV 0x3CU /* EEE advertisement */ + +/*! @brief MDIO MMD EEE mask flags. (common for adv and cap) */ +#define PHY_MDIO_EEE_100TX 0x2U +#define PHY_MDIO_EEE_1000T 0x4U + +/*! @brief Defines the timeout macro. */ +#define PHY_READID_TIMEOUT_COUNT 1000U + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +const phy_operations_t phyksz9131rnx_ops = {.phyInit = PHY_KSZ9131RNX_Init, + .phyWrite = PHY_KSZ9131RNX_Write, + .phyRead = PHY_KSZ9131RNX_Read, + .getAutoNegoStatus = PHY_KSZ9131RNX_GetAutoNegotiationStatus, + .getLinkStatus = PHY_KSZ9131RNX_GetLinkStatus, + .getLinkSpeedDuplex = PHY_KSZ9131RNX_GetLinkSpeedDuplex, + .setLinkSpeedDuplex = PHY_KSZ9131RNX_SetLinkSpeedDuplex, + .enableLoopback = PHY_KSZ9131RNX_EnableLoopback}; + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_KSZ9131RNX_Init(phy_handle_t *handle, const phy_config_t *config) +{ + uint32_t counter = PHY_READID_TIMEOUT_COUNT; + status_t result; + uint32_t regValue = 0U; + + /* Init MDIO interface. */ + MDIO_Init(handle->mdioHandle); + + /* Assign phy address. */ + handle->phyAddr = config->phyAddr; + + /* Check PHY ID. */ + do + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_ID1_REG, ®Value); + if (result != kStatus_Success) + { + return result; + } + counter--; + } while ((regValue != PHY_CONTROL_ID1) && (counter != 0U)); + + if (counter == 0U) + { + return kStatus_Fail; + } + + /* Reset PHY. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result != kStatus_Success) + { + return result; + } + + /* Set the negotiation. */ + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK | + PHY_10BASETX_HALFDUPLEX_MASK)); + if (result == kStatus_Success) + { + result = + MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_1000BASET_CONTROL_REG, PHY_1000BASET_FULLDUPLEX_MASK); + if (result == kStatus_Success) + { + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + + return result; +} + +status_t PHY_KSZ9131RNX_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) +{ + return MDIO_Write(handle->mdioHandle, handle->phyAddr, phyReg, data); +} + +status_t PHY_KSZ9131RNX_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) +{ + return MDIO_Read(handle->mdioHandle, handle->phyAddr, phyReg, dataPtr); +} + +status_t PHY_KSZ9131RNX_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) +{ + assert(status); + + status_t result; + uint32_t regValue; + + *status = false; + + /* Check auto negotiation complete. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICSTATUS_REG, ®Value); + if (result == kStatus_Success) + { + if ((regValue & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0U) + { + *status = true; + } + } + return result; +} + +status_t PHY_KSZ9131RNX_GetLinkStatus(phy_handle_t *handle, bool *status) +{ + assert(status); + + status_t result; + uint32_t regValue; + + /* Read the basic status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_SPECIFIC_STATUS_REG, ®Value); + if (result == kStatus_Success) + { + if ((PHY_SSTATUS_LINKSTATUS_MASK & regValue) != 0U) + { + /* Link up. */ + *status = true; + } + else + { + /* Link down. */ + *status = false; + } + } + return result; +} + +status_t PHY_KSZ9131RNX_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) +{ + assert(!((speed == NULL) && (duplex == NULL))); + + status_t result; + uint32_t regValue; + + /* Read the status register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_SPECIFIC_STATUS_REG, ®Value); + if (result == kStatus_Success) + { + if (speed != NULL) + { + switch ((regValue & PHY_SSTATUS_LINKSPEED_MASK) >> PHY_SSTATUS_LINKSPEED_SHIFT) + { + case (uint32_t)kPHY_Speed10M: + *speed = kPHY_Speed10M; + break; + case (uint32_t)kPHY_Speed100M: + *speed = kPHY_Speed100M; + break; + case (uint32_t)kPHY_Speed1000M: + *speed = kPHY_Speed1000M; + break; + default: + *speed = kPHY_Speed10M; + break; + } + } + + if (duplex != NULL) + { + if ((regValue & PHY_SSTATUS_LINKDUPLEX_MASK) != 0U) + { + *duplex = kPHY_FullDuplex; + } + else + { + *duplex = kPHY_HalfDuplex; + } + } + } + return result; +} + +status_t PHY_KSZ9131RNX_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) +{ + status_t result; + uint32_t regValue; + + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) + { + /* Disable the auto-negotiation and set according to user-defined configuration. */ + regValue &= ~PHY_BCTL_AUTONEG_MASK; + if (speed == kPHY_Speed1000M) + { + regValue &= PHY_BCTL_SPEED0_MASK; + regValue |= PHY_BCTL_SPEED1_MASK; + } + else if (speed == kPHY_Speed100M) + { + regValue |= PHY_BCTL_SPEED0_MASK; + regValue &= ~PHY_BCTL_SPEED1_MASK; + } + else + { + regValue &= ~PHY_BCTL_SPEED0_MASK; + regValue &= ~PHY_BCTL_SPEED1_MASK; + } + if (duplex == kPHY_FullDuplex) + { + regValue |= PHY_BCTL_DUPLEX_MASK; + } + else + { + regValue &= ~PHY_BCTL_DUPLEX_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + return result; +} + +status_t PHY_KSZ9131RNX_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) +{ + /* This PHY only supports local loopback. */ + assert(mode == kPHY_LocalLoop); + + status_t result; + uint32_t regValue; + + /* Set the loop mode. */ + if (enable) + { + if (speed == kPHY_Speed1000M) + { + regValue = PHY_BCTL_SPEED1_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + else if (speed == kPHY_Speed100M) + { + regValue = PHY_BCTL_SPEED0_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + else + { + regValue = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, regValue); + } + else + { + /* First read the current status in control register. */ + result = MDIO_Read(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, ®Value); + if (result == kStatus_Success) + { + regValue &= ~PHY_BCTL_LOOP_MASK; + result = MDIO_Write(handle->mdioHandle, handle->phyAddr, PHY_BASICCONTROL_REG, + (regValue | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + return result; +} diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/fsl_phyksz9131rnx.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/fsl_phyksz9131rnx.h new file mode 100644 index 000000000..1c4895ddb --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/ethernet/phy/ksz9131rnx/fsl_phyksz9131rnx.h @@ -0,0 +1,163 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/***************************************************************************** + * PHY KSZ9131RNX driver change log + *****************************************************************************/ + +/*! +@page driver_log Driver Change Log + +@section phyrtl8211 PHYKSZ9131RNX + The current PHYKSZ9131RNX driver version is 2.0.0. + + - 2.0.0 + - Initial version. +*/ + +#ifndef _FSL_PHYKSZ9131RNX_H_ +#define _FSL_PHYKSZ9131RNX_H_ + +#include "fsl_phy.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) + +/*! @brief PHY operations structure. */ +extern const phy_operations_t phyksz9131rnx_ops; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_Init(phy_handle_t *handle, const phy_config_t *config); + +/*! + * @brief PHY Write function. This function writes data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + +/*! + * @brief PHY Read function. This interface reads data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY gets link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_GetLinkStatus(phy_handle_t *handle, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY gets link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY loopback success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +status_t PHY_KSZ9131RNX_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHY_H_ */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/gpio/Makefile b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/gpio/Makefile index a69677383..2776af734 100755 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/gpio/Makefile +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/gpio/Makefile @@ -1,3 +1,3 @@ -SRC_FILES := connect_gpio.c fsl_gpio.c +SRC_FILES := fsl_gpio.c include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/connect_ethernet.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/connect_ethernet.h new file mode 100755 index 000000000..12f65358b --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/connect_ethernet.h @@ -0,0 +1,42 @@ +/* +* Copyright (c) 2021 AIIT XUOS Lab +* XiUOS is licensed under Mulan PSL v2. +* You can use this software according to the terms and conditions of the Mulan PSL v2. +* You may obtain a copy of Mulan PSL v2 at: +* http://license.coscl.org.cn/MulanPSL2 +* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, +* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, +* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +* See the Mulan PSL v2 for more details. +*/ + +/** +* @file connect_ethernet.h +* @brief Adapted network software protocol stack and hardware operation functions +* @version 1.0 +* @author AIIT XUOS Lab +* @date 2021-12-7 +*/ + +#ifndef __CONNECT_ETHERNET_H_ +#define __CONNECT_ETHERNET_H_ + +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifndef sourceClock +#define sourceClock CLOCK_GetFreq(kCLOCK_CoreSysClk) +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/enet_ethernetif.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/enet_ethernetif.h new file mode 100644 index 000000000..ca5ade06b --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/enet_ethernetif.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels + * + */ + +/* + * Copyright (c) 2013-2016, Freescale Semiconductor, Inc. + * Copyright 2016-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ENET_ETHERNETIF_H +#define ENET_ETHERNETIF_H + +#include "lwip/err.h" +#include "lwip/netif.h" +#include "fsl_phy.h" +#include +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT +#include "fsl_phyksz8081.h" +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT +#include "fsl_phyksz9131rnx.h" +#endif +#include "fsl_enet_mdio.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifdef BOARD_NETWORK_USE_100M_ENET_PORT +/* Address of PHY interface. */ +#define EXAMPLE_ENET0_PHY_ADDRESS BOARD_ENET0_PHY_ADDRESS +/* PHY operations. */ +#define EXAMPLE_ENET0_PHY_OPS phyksz8081_ops +/* ENET instance select. */ +#define NETIF_ENET0_INIT_FUNC ethernetif0_init +#endif + +#ifdef BOARD_NETWORK_USE_1G_ENET_PORT +/* Address of PHY interface. */ +#define EXAMPLE_ENET1_PHY_ADDRESS BOARD_ENET1_PHY_ADDRESS +/* PHY operations. */ +#define EXAMPLE_ENET1_PHY_OPS phyksz9131rnx_ops +/* ENET instance select. */ +#define NETIF_ENET1_INIT_FUNC ethernetif1_init +#endif + +/* MDIO operations. */ +#define EXAMPLE_MDIO_OPS enet_ops + +/* ENET clock frequency. */ +#define EXAMPLE_CLOCK_FREQ CLOCK_GetRootClockFreq(kCLOCK_Root_Bus) + +#define ENET_TIMEOUT (0xFFFU) + +/* ENET IRQ priority. Used in FreeRTOS. */ +/* Interrupt priorities. */ +#ifdef __CA7_REV +#ifndef ENET_PRIORITY + #define ENET_PRIORITY (21U) +#endif +#ifndef ENET_1588_PRIORITY + #define ENET_1588_PRIORITY (20U) +#endif +#else +#ifndef ENET_PRIORITY + #define ENET_PRIORITY (6U) +#endif +#ifndef ENET_1588_PRIORITY + #define ENET_1588_PRIORITY (5U) +#endif +#endif + +/* Defines Ethernet Autonegotiation Timeout during initialization. + * Set it to 0 to disable the waiting. */ +#ifndef ENET_ATONEGOTIATION_TIMEOUT + #define ENET_ATONEGOTIATION_TIMEOUT (0x2FFFFU) +#endif + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +#define ENET_RING_NUM 1U + +#if (defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)) +typedef struct mem_range +{ + uint32_t start; + uint32_t end; +} mem_range_t; +#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ + +/** + * Helper struct to hold data for configuration of ethernet interface. + */ +typedef struct ethernetif_config +{ + phy_handle_t *phyHandle; + uint8_t macAddress[NETIF_MAX_HWADDR_LEN]; +#if (defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0)) + const mem_range_t *non_dma_memory; +#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ +} ethernetif_config_t; + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +/** + * This function should be passed as a parameter to netif_add() + * if you initialize the first ENET interface. + */ +err_t ethernetif0_init(struct netif *netif); + +#if (defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 1)) \ + || (defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 1)) +/** + * This function should be passed as a parameter to netif_add() + * if you initialize the second ENET interface. + */ +err_t ethernetif1_init(struct netif *netif); +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ + +/** + * This function should be called when a packet is ready to be read + * from the interface. + * It is used by bare-metal applications. + * + * @param netif the lwip network interface structure for this ethernetif + */ +void ethernetif_input( struct netif *netif); + +int ETH_BSP_Config(void); +void *ethernetif_config_enet_set(uint8_t enet_port); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* ENET_ETHERNETIF_H */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/enet_ethernetif_priv.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/enet_ethernetif_priv.h new file mode 100644 index 000000000..9ba9a862f --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/enet_ethernetif_priv.h @@ -0,0 +1,80 @@ +/* + * Copyright 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef ENET_ETHERNETIF_PRIV_H +#define ENET_ETHERNETIF_PRIV_H + +#include "lwip/err.h" + +struct ethernetif; + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus */ + +err_t ethernetif_init(struct netif *netif, struct ethernetif *ethernetif, + void *enetBase, + const ethernetif_config_t *ethernetifConfig); + +void ethernetif_enet_init(struct netif *netif, struct ethernetif *ethernetif, + const ethernetif_config_t *ethernetifConfig); + +void ethernetif_phy_init(struct ethernetif *ethernetif, + const ethernetif_config_t *ethernetifConfig, + phy_speed_t *speed, + phy_duplex_t *duplex); + +void *ethernetif_get_enet_base(const uint8_t enetIdx); + +#if defined(FSL_FEATURE_SOC_ENET_QOS_COUNT) && (FSL_FEATURE_SOC_ENET_QOS_COUNT > 0) +void *ethernetif_get_enet_qos_base(const uint8_t enetIdx); +#endif + +void **ethernetif_enet_ptr(struct ethernetif *ethernetif); + +#if LWIP_IPV4 && LWIP_IGMP +err_t ethernetif_igmp_mac_filter(struct netif *netif, const ip4_addr_t *group, + enum netif_mac_filter_action action); +#endif + +#if LWIP_IPV6 && LWIP_IPV6_MLD +err_t ethernetif_mld_mac_filter(struct netif *netif, const ip6_addr_t *group, + enum netif_mac_filter_action action); +#endif + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + * NULL on memory error + */ +struct pbuf *ethernetif_linkinput(struct netif *netif); + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + * an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + * strange results. You might consider waiting for space in the DMA queue + * to become available since the stack doesn't retry to send a packet + * dropped because of memory failure (except for the TCP timers). + */ +err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* ENET_ETHERNETIF_PRIV_H */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_device_registers.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_device_registers.h index eff2194a3..ab815fc15 100644 --- a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_device_registers.h +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_device_registers.h @@ -28,7 +28,6 @@ Modification: #ifndef __FSL_DEVICE_REGISTERS_H__ #define __FSL_DEVICE_REGISTERS_H__ -#define CPU_MIMXRT1176DVMAA_cm7 /* * Include the cpu specific register header files. * diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_enet.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_enet.h new file mode 100644 index 000000000..c0bc97f3e --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_enet.h @@ -0,0 +1,1993 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_ENET_H_ +#define _FSL_ENET_H_ + +#include "fsl_common.h" +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET +#include "fsl_memory.h" +#endif +/*! + * @addtogroup enet + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief Defines the driver version. */ +#define FSL_ENET_DRIVER_VERSION (MAKE_VERSION(2, 5, 3)) +/*@}*/ + +/*! @name ENET DESCRIPTOR QUEUE */ +/*@{*/ +/*! @brief Defines the queue number. */ +#ifndef FSL_FEATURE_ENET_QUEUE +#define FSL_FEATURE_ENET_QUEUE 1 /* Singal queue for previous IP. */ +#endif +/*@}*/ + +/*! @name Control and status region bit masks of the receive buffer descriptor. */ +/*@{*/ +#define ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK 0x8000U /*!< Empty bit mask. */ +#define ENET_BUFFDESCRIPTOR_RX_SOFTOWNER1_MASK 0x4000U /*!< Software owner one mask. */ +#define ENET_BUFFDESCRIPTOR_RX_WRAP_MASK 0x2000U /*!< Next buffer descriptor is the start address. */ +#define ENET_BUFFDESCRIPTOR_RX_SOFTOWNER2_Mask 0x1000U /*!< Software owner two mask. */ +#define ENET_BUFFDESCRIPTOR_RX_LAST_MASK 0x0800U /*!< Last BD of the frame mask. */ +#define ENET_BUFFDESCRIPTOR_RX_MISS_MASK 0x0100U /*!< Received because of the promiscuous mode. */ +#define ENET_BUFFDESCRIPTOR_RX_BROADCAST_MASK 0x0080U /*!< Broadcast packet mask. */ +#define ENET_BUFFDESCRIPTOR_RX_MULTICAST_MASK 0x0040U /*!< Multicast packet mask. */ +#define ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK 0x0020U /*!< Length violation mask. */ +#define ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK 0x0010U /*!< Non-octet aligned frame mask. */ +#define ENET_BUFFDESCRIPTOR_RX_CRC_MASK 0x0004U /*!< CRC error mask. */ +#define ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK 0x0002U /*!< FIFO overrun mask. */ +#define ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK 0x0001U /*!< Frame is truncated mask. */ +/*@}*/ + +/*! @name Control and status bit masks of the transmit buffer descriptor. */ +/*@{*/ +#define ENET_BUFFDESCRIPTOR_TX_READY_MASK 0x8000U /*!< Ready bit mask. */ +#define ENET_BUFFDESCRIPTOR_TX_SOFTOWENER1_MASK 0x4000U /*!< Software owner one mask. */ +#define ENET_BUFFDESCRIPTOR_TX_WRAP_MASK 0x2000U /*!< Wrap buffer descriptor mask. */ +#define ENET_BUFFDESCRIPTOR_TX_SOFTOWENER2_MASK 0x1000U /*!< Software owner two mask. */ +#define ENET_BUFFDESCRIPTOR_TX_LAST_MASK 0x0800U /*!< Last BD of the frame mask. */ +#define ENET_BUFFDESCRIPTOR_TX_TRANMITCRC_MASK 0x0400U /*!< Transmit CRC mask. */ +/*@}*/ + +/* Extended control regions for enhanced buffer descriptors. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! @name First extended control region bit masks of the receive buffer descriptor. */ +/*@{*/ +#define ENET_BUFFDESCRIPTOR_RX_IPV4_MASK 0x0001U /*!< Ipv4 frame mask. */ +#define ENET_BUFFDESCRIPTOR_RX_IPV6_MASK 0x0002U /*!< Ipv6 frame mask. */ +#define ENET_BUFFDESCRIPTOR_RX_VLAN_MASK 0x0004U /*!< VLAN frame mask. */ +#define ENET_BUFFDESCRIPTOR_RX_PROTOCOLCHECKSUM_MASK 0x0010U /*!< Protocol checksum error mask. */ +#define ENET_BUFFDESCRIPTOR_RX_IPHEADCHECKSUM_MASK 0x0020U /*!< IP header checksum error mask. */ +/*@}*/ + +/*! @name Second extended control region bit masks of the receive buffer descriptor. */ +/*@{*/ +#define ENET_BUFFDESCRIPTOR_RX_INTERRUPT_MASK 0x0080U /*!< BD interrupt mask. */ +#define ENET_BUFFDESCRIPTOR_RX_UNICAST_MASK 0x0100U /*!< Unicast frame mask. */ +#define ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK 0x0200U /*!< BD collision mask. */ +#define ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK 0x0400U /*!< PHY error mask. */ +#define ENET_BUFFDESCRIPTOR_RX_MACERR_MASK 0x8000U /*!< Mac error mask. */ +/*@}*/ + +/*! @name First extended control region bit masks of the transmit buffer descriptor. */ +/*@{*/ +#define ENET_BUFFDESCRIPTOR_TX_ERR_MASK 0x8000U /*!< Transmit error mask. */ +#define ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK 0x2000U /*!< Underflow error mask. */ +#define ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK 0x1000U /*!< Excess collision error mask. */ +#define ENET_BUFFDESCRIPTOR_TX_FRAMEERR_MASK 0x0800U /*!< Frame error mask. */ +#define ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK 0x0400U /*!< Late collision error mask. */ +#define ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK 0x0200U /*!< Overflow error mask. */ +#define ENET_BUFFDESCRIPTOR_TX_TIMESTAMPERR_MASK 0x0100U /*!< Timestamp error mask. */ +/*@}*/ + +/*! @name Second extended control region bit masks of the transmit buffer descriptor. */ +/*@{*/ +#define ENET_BUFFDESCRIPTOR_TX_INTERRUPT_MASK 0x4000U /*!< Interrupt mask. */ +#define ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK 0x2000U /*!< Timestamp flag mask. */ +#define ENET_BUFFDESCRIPTOR_TX_PROTOCHECKSUM_MASK 0x1000U /*!< Protocal checksum mask. */ +#define ENET_BUFFDESCRIPTOR_TX_IPCHECKSUM_MASK 0x0800U /*!< IP header checksum flag mask. */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB +#define ENET_BUFFDESCRIPTOR_TX_USETXLAUNCHTIME_MASK 0x0100U /*!< Use the transmit launch time. */ +#define ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_MASK 0x00F0U /*!< Frame type mask. */ +#define ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_SHIFT 4U /*!< Frame type shift. */ +#define ENET_BD_FTYPE(n) \ + (((uint32_t)(n) << ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_SHIFT) & ENET_BUFFDESCRIPTOR_TX_FRAMETYPE_MASK) +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +/*@}*/ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! @brief Defines the receive error status flag mask. */ +#define ENET_BUFFDESCRIPTOR_RX_ERR_MASK \ + (ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK | ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK | \ + ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK | ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK | ENET_BUFFDESCRIPTOR_RX_CRC_MASK) +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +#define ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK \ + (ENET_BUFFDESCRIPTOR_RX_MACERR_MASK | ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK | ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK) +#endif + +/*! @name Defines some Ethernet parameters. */ +/*@{*/ +#define ENET_FRAME_MAX_FRAMELEN 1518U /*!< Default maximum Ethernet frame size without VLAN tag. */ +#define ENET_FRAME_VLAN_TAGLEN 4U /*!< Ethernet single VLAN tag size. */ +#define ENET_FRAME_CRC_LEN 4U /*!< CRC size in a frame. */ +#define ENET_FRAME_TX_LEN_LIMITATION(x) \ + ((((x)->RCR & ENET_RCR_MAX_FL_MASK) >> ENET_RCR_MAX_FL_SHIFT) - ENET_FRAME_CRC_LEN) + +#define ENET_FIFO_MIN_RX_FULL 5U /*!< ENET minimum receive FIFO full. */ +#define ENET_RX_MIN_BUFFERSIZE 256U /*!< ENET minimum buffer size. */ +#define ENET_PHY_MAXADDRESS (ENET_MMFR_PA_MASK >> ENET_MMFR_PA_SHIFT) /*!< Maximum PHY address. */ + +#if FSL_FEATURE_ENET_QUEUE > 1 +#define ENET_TX_INTERRUPT \ + ((uint32_t)kENET_TxFrameInterrupt | (uint32_t)kENET_TxBufferInterrupt | (uint32_t)kENET_TxFrame1Interrupt | \ + (uint32_t)kENET_TxBuffer1Interrupt | (uint32_t)kENET_TxFrame2Interrupt | \ + (uint32_t)kENET_TxBuffer2Interrupt) /*!< Enet Tx interrupt flag. */ +#define ENET_RX_INTERRUPT \ + ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt | (uint32_t)kENET_RxFrame1Interrupt | \ + (uint32_t)kENET_RxBuffer1Interrupt | (uint32_t)kENET_RxFrame2Interrupt | \ + (uint32_t)kENET_RxBuffer2Interrupt) /*!< Enet Rx interrupt flag. */ +#else +#define ENET_TX_INTERRUPT \ + ((uint32_t)kENET_TxFrameInterrupt | (uint32_t)kENET_TxBufferInterrupt) /*!< Enet Tx interrupt flag. */ +#define ENET_RX_INTERRUPT \ + ((uint32_t)kENET_RxFrameInterrupt | (uint32_t)kENET_RxBufferInterrupt) /*!< Enet Rx interrupt flag. */ +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +#define ENET_TS_INTERRUPT \ + ((uint32_t)kENET_TsTimerInterrupt | (uint32_t)kENET_TsAvailInterrupt) /*!< Enet timestamp interrupt flag. */ +#define ENET_ERR_INTERRUPT \ + ((uint32_t)kENET_BabrInterrupt | (uint32_t)kENET_BabtInterrupt | (uint32_t)kENET_EBusERInterrupt | \ + (uint32_t)kENET_LateCollisionInterrupt | (uint32_t)kENET_RetryLimitInterrupt | \ + (uint32_t)kENET_UnderrunInterrupt | (uint32_t)kENET_PayloadRxInterrupt) /*!< Enet error interrupt flag. */ +/*@}*/ + +/*! @brief Defines the status return codes for transaction. */ +enum +{ + kStatus_ENET_InitMemoryFail = + MAKE_STATUS(kStatusGroup_ENET, 0U), /*!< Init fails since buffer memory is not enough. */ + kStatus_ENET_RxFrameError = MAKE_STATUS(kStatusGroup_ENET, 1U), /*!< A frame received but data error happen. */ + kStatus_ENET_RxFrameFail = MAKE_STATUS(kStatusGroup_ENET, 2U), /*!< Failed to receive a frame. */ + kStatus_ENET_RxFrameEmpty = MAKE_STATUS(kStatusGroup_ENET, 3U), /*!< No frame arrive. */ + kStatus_ENET_RxFrameDrop = MAKE_STATUS(kStatusGroup_ENET, 4U), /*!< Rx frame is dropped since no buffer memory. */ + kStatus_ENET_TxFrameOverLen = MAKE_STATUS(kStatusGroup_ENET, 5U), /*!< Tx frame over length. */ + kStatus_ENET_TxFrameBusy = MAKE_STATUS(kStatusGroup_ENET, 6U), /*!< Tx buffer descriptors are under process. */ + kStatus_ENET_TxFrameFail = MAKE_STATUS(kStatusGroup_ENET, 7U), /*!< Transmit frame fail. */ +}; + +/*! @brief Defines the MII/RMII/RGMII mode for data interface between the MAC and the PHY. */ +typedef enum _enet_mii_mode +{ + kENET_MiiMode = 0U, /*!< MII mode for data interface. */ + kENET_RmiiMode = 1U, /*!< RMII mode for data interface. */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + kENET_RgmiiMode = 2U /*!< RGMII mode for data interface. */ +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +} enet_mii_mode_t; + +/*! @brief Defines the 10/100/1000 Mbps speed for the MII data interface. + * + * Notice: "kENET_MiiSpeed1000M" only supported when mii mode is "kENET_RgmiiMode". + */ +typedef enum _enet_mii_speed +{ + kENET_MiiSpeed10M = 0U, /*!< Speed 10 Mbps. */ + kENET_MiiSpeed100M = 1U, /*!< Speed 100 Mbps. */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + kENET_MiiSpeed1000M = 2U /*!< Speed 1000M bps. */ +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +} enet_mii_speed_t; + +/*! @brief Defines the half or full duplex for the MII data interface. */ +typedef enum _enet_mii_duplex +{ + kENET_MiiHalfDuplex = 0U, /*!< Half duplex mode. */ + kENET_MiiFullDuplex /*!< Full duplex mode. */ +} enet_mii_duplex_t; + +/*! @brief Define the MII opcode for normal MDIO_CLAUSES_22 Frame. */ +typedef enum _enet_mii_write +{ + kENET_MiiWriteNoCompliant = 0U, /*!< Write frame operation, but not MII-compliant. */ + kENET_MiiWriteValidFrame /*!< Write frame operation for a valid MII management frame. */ +} enet_mii_write_t; + +/*! @brief Defines the read operation for the MII management frame. */ +typedef enum _enet_mii_read +{ + kENET_MiiReadValidFrame = 2U, /*!< Read frame operation for a valid MII management frame. */ + kENET_MiiReadNoCompliant = 3U /*!< Read frame operation, but not MII-compliant. */ +} enet_mii_read_t; + +#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO +/*! @brief Define the MII opcode for extended MDIO_CLAUSES_45 Frame. */ +typedef enum _enet_mii_extend_opcode +{ + kENET_MiiAddrWrite_C45 = 0U, /*!< Address Write operation. */ + kENET_MiiWriteFrame_C45 = 1U, /*!< Write frame operation for a valid MII management frame. */ + kENET_MiiReadFrame_C45 = 3U /*!< Read frame operation for a valid MII management frame. */ +} enet_mii_extend_opcode; +#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */ + +/*! @brief Defines a special configuration for ENET MAC controller. + * + * These control flags are provided for special user requirements. + * Normally, these control flags are unused for ENET initialization. + * For special requirements, set the flags to + * macSpecialConfig in the enet_config_t. + * The kENET_ControlStoreAndFwdDisable is used to disable the FIFO store + * and forward. FIFO store and forward means that the FIFO read/send is started + * when a complete frame is stored in TX/RX FIFO. If this flag is set, + * configure rxFifoFullThreshold and txFifoWatermark + * in the enet_config_t. + */ +typedef enum _enet_special_control_flag +{ + kENET_ControlFlowControlEnable = 0x0001U, /*!< Enable ENET flow control: pause frame. */ + kENET_ControlRxPayloadCheckEnable = 0x0002U, /*!< Enable ENET receive payload length check. */ + kENET_ControlRxPadRemoveEnable = 0x0004U, /*!< Padding is removed from received frames. */ + kENET_ControlRxBroadCastRejectEnable = 0x0008U, /*!< Enable broadcast frame reject. */ + kENET_ControlMacAddrInsert = 0x0010U, /*!< Enable MAC address insert. */ + kENET_ControlStoreAndFwdDisable = 0x0020U, /*!< Enable FIFO store and forward. */ + kENET_ControlSMIPreambleDisable = 0x0040U, /*!< Enable SMI preamble. */ + kENET_ControlPromiscuousEnable = 0x0080U, /*!< Enable promiscuous mode. */ + kENET_ControlMIILoopEnable = 0x0100U, /*!< Enable ENET MII loop back. */ + kENET_ControlVLANTagEnable = 0x0200U, /*!< Enable normal VLAN (single vlan tag). */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + kENET_ControlSVLANEnable = 0x0400U, /*!< Enable S-VLAN. */ + kENET_ControlVLANUseSecondTag = 0x0800U /*!< Enable extracting the second vlan tag for further processing. */ +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +} enet_special_control_flag_t; + +/*! @brief List of interrupts supported by the peripheral. This + * enumeration uses one-bit encoding to allow a logical OR of multiple + * members. Members usually map to interrupt enable bits in one or more + * peripheral registers. + */ +typedef enum _enet_interrupt_enable +{ + kENET_BabrInterrupt = ENET_EIR_BABR_MASK, /*!< Babbling receive error interrupt source */ + kENET_BabtInterrupt = ENET_EIR_BABT_MASK, /*!< Babbling transmit error interrupt source */ + kENET_GraceStopInterrupt = ENET_EIR_GRA_MASK, /*!< Graceful stop complete interrupt source */ + kENET_TxFrameInterrupt = ENET_EIR_TXF_MASK, /*!< TX FRAME interrupt source */ + kENET_TxBufferInterrupt = ENET_EIR_TXB_MASK, /*!< TX BUFFER interrupt source */ + kENET_RxFrameInterrupt = ENET_EIR_RXF_MASK, /*!< RX FRAME interrupt source */ + kENET_RxBufferInterrupt = ENET_EIR_RXB_MASK, /*!< RX BUFFER interrupt source */ + kENET_MiiInterrupt = ENET_EIR_MII_MASK, /*!< MII interrupt source */ + kENET_EBusERInterrupt = ENET_EIR_EBERR_MASK, /*!< Ethernet bus error interrupt source */ + kENET_LateCollisionInterrupt = ENET_EIR_LC_MASK, /*!< Late collision interrupt source */ + kENET_RetryLimitInterrupt = ENET_EIR_RL_MASK, /*!< Collision Retry Limit interrupt source */ + kENET_UnderrunInterrupt = ENET_EIR_UN_MASK, /*!< Transmit FIFO underrun interrupt source */ + kENET_PayloadRxInterrupt = ENET_EIR_PLR_MASK, /*!< Payload Receive error interrupt source */ + kENET_WakeupInterrupt = ENET_EIR_WAKEUP_MASK, /*!< WAKEUP interrupt source */ +#if FSL_FEATURE_ENET_QUEUE > 1 + kENET_RxFlush2Interrupt = ENET_EIR_RXFLUSH_2_MASK, /*!< Rx DMA ring2 flush indication. */ + kENET_RxFlush1Interrupt = ENET_EIR_RXFLUSH_1_MASK, /*!< Rx DMA ring1 flush indication. */ + kENET_RxFlush0Interrupt = ENET_EIR_RXFLUSH_0_MASK, /*!< RX DMA ring0 flush indication. */ + kENET_TxFrame2Interrupt = ENET_EIR_TXF2_MASK, /*!< Tx frame interrupt for Tx ring/class 2. */ + kENET_TxBuffer2Interrupt = ENET_EIR_TXB2_MASK, /*!< Tx buffer interrupt for Tx ring/class 2. */ + kENET_RxFrame2Interrupt = ENET_EIR_RXF2_MASK, /*!< Rx frame interrupt for Rx ring/class 2. */ + kENET_RxBuffer2Interrupt = ENET_EIR_RXB2_MASK, /*!< Rx buffer interrupt for Rx ring/class 2. */ + kENET_TxFrame1Interrupt = ENET_EIR_TXF1_MASK, /*!< Tx frame interrupt for Tx ring/class 1. */ + kENET_TxBuffer1Interrupt = ENET_EIR_TXB1_MASK, /*!< Tx buffer interrupt for Tx ring/class 1. */ + kENET_RxFrame1Interrupt = ENET_EIR_RXF1_MASK, /*!< Rx frame interrupt for Rx ring/class 1. */ + kENET_RxBuffer1Interrupt = ENET_EIR_RXB1_MASK, /*!< Rx buffer interrupt for Rx ring/class 1. */ +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + kENET_TsAvailInterrupt = ENET_EIR_TS_AVAIL_MASK, /*!< TS AVAIL interrupt source for PTP */ + kENET_TsTimerInterrupt = ENET_EIR_TS_TIMER_MASK /*!< TS WRAP interrupt source for PTP */ +} enet_interrupt_enable_t; + +/*! @brief Defines the common interrupt event for callback use. */ +typedef enum _enet_event +{ + kENET_RxEvent, /*!< Receive event. */ + kENET_TxEvent, /*!< Transmit event. */ + kENET_ErrEvent, /*!< Error event: BABR/BABT/EBERR/LC/RL/UN/PLR . */ + kENET_WakeUpEvent, /*!< Wake up from sleep mode event. */ + kENET_TimeStampEvent, /*!< Time stamp event. */ + kENET_TimeStampAvailEvent /*!< Time stamp available event.*/ +} enet_event_t; + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB +/*! @brief Defines certain idle slope for bandwidth fraction. */ +typedef enum _enet_idle_slope +{ + kENET_IdleSlope1 = 1U, /*!< The bandwidth fraction is about 0.002. */ + kENET_IdleSlope2 = 2U, /*!< The bandwidth fraction is about 0.003. */ + kENET_IdleSlope4 = 4U, /*!< The bandwidth fraction is about 0.008. */ + kENET_IdleSlope8 = 8U, /*!< The bandwidth fraction is about 0.02. */ + kENET_IdleSlope16 = 16U, /*!< The bandwidth fraction is about 0.03. */ + kENET_IdleSlope32 = 32U, /*!< The bandwidth fraction is about 0.06. */ + kENET_IdleSlope64 = 64U, /*!< The bandwidth fraction is about 0.11. */ + kENET_IdleSlope128 = 128U, /*!< The bandwidth fraction is about 0.20. */ + kENET_IdleSlope256 = 256U, /*!< The bandwidth fraction is about 0.33. */ + kENET_IdleSlope384 = 384U, /*!< The bandwidth fraction is about 0.43. */ + kENET_IdleSlope512 = 512U, /*!< The bandwidth fraction is about 0.50. */ + kENET_IdleSlope640 = 640U, /*!< The bandwidth fraction is about 0.56. */ + kENET_IdleSlope768 = 768U, /*!< The bandwidth fraction is about 0.60. */ + kENET_IdleSlope896 = 896U, /*!< The bandwidth fraction is about 0.64. */ + kENET_IdleSlope1024 = 1024U, /*!< The bandwidth fraction is about 0.67. */ + kENET_IdleSlope1152 = 1152U, /*!< The bandwidth fraction is about 0.69. */ + kENET_IdleSlope1280 = 1280U, /*!< The bandwidth fraction is about 0.71. */ + kENET_IdleSlope1408 = 1408U, /*!< The bandwidth fraction is about 0.73. */ + kENET_IdleSlope1536 = 1536U /*!< The bandwidth fraction is about 0.75. */ +} enet_idle_slope_t; +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + +/*! @brief Defines the transmit accelerator configuration. */ +typedef enum _enet_tx_accelerator +{ + kENET_TxAccelIsShift16Enabled = ENET_TACC_SHIFT16_MASK, /*!< Transmit FIFO shift-16. */ + kENET_TxAccelIpCheckEnabled = ENET_TACC_IPCHK_MASK, /*!< Insert IP header checksum. */ + kENET_TxAccelProtoCheckEnabled = ENET_TACC_PROCHK_MASK /*!< Insert protocol checksum. */ +} enet_tx_accelerator_t; + +/*! @brief Defines the receive accelerator configuration. */ +typedef enum _enet_rx_accelerator +{ + kENET_RxAccelPadRemoveEnabled = ENET_RACC_PADREM_MASK, /*!< Padding removal for short IP frames. */ + kENET_RxAccelIpCheckEnabled = ENET_RACC_IPDIS_MASK, /*!< Discard with wrong IP header checksum. */ + kENET_RxAccelProtoCheckEnabled = ENET_RACC_PRODIS_MASK, /*!< Discard with wrong protocol checksum. */ + kENET_RxAccelMacCheckEnabled = ENET_RACC_LINEDIS_MASK, /*!< Discard with Mac layer errors. */ + kENET_RxAccelisShift16Enabled = ENET_RACC_SHIFT16_MASK /*!< Receive FIFO shift-16. */ +} enet_rx_accelerator_t; + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! @brief Defines the ENET PTP message related constant. */ +typedef enum _enet_ptp_event_type +{ + kENET_PtpEventMsgType = 3U, /*!< PTP event message type. */ + kENET_PtpSrcPortIdLen = 10U, /*!< PTP message sequence id length. */ + kENET_PtpEventPort = 319U, /*!< PTP event port number. */ + kENET_PtpGnrlPort = 320U /*!< PTP general port number. */ +} enet_ptp_event_type_t; + +/*! @brief Defines the IEEE 1588 PTP timer channel numbers. */ +typedef enum _enet_ptp_timer_channel +{ + kENET_PtpTimerChannel1 = 0U, /*!< IEEE 1588 PTP timer Channel 1. */ + kENET_PtpTimerChannel2, /*!< IEEE 1588 PTP timer Channel 2. */ + kENET_PtpTimerChannel3, /*!< IEEE 1588 PTP timer Channel 3. */ + kENET_PtpTimerChannel4 /*!< IEEE 1588 PTP timer Channel 4. */ +} enet_ptp_timer_channel_t; + +/*! @brief Defines the capture or compare mode for IEEE 1588 PTP timer channels. */ +typedef enum _enet_ptp_timer_channel_mode +{ + kENET_PtpChannelDisable = 0U, /*!< Disable timer channel. */ + kENET_PtpChannelRisingCapture = 1U, /*!< Input capture on rising edge. */ + kENET_PtpChannelFallingCapture = 2U, /*!< Input capture on falling edge. */ + kENET_PtpChannelBothCapture = 3U, /*!< Input capture on both edges. */ + kENET_PtpChannelSoftCompare = 4U, /*!< Output compare software only. */ + kENET_PtpChannelToggleCompare = 5U, /*!< Toggle output on compare. */ + kENET_PtpChannelClearCompare = 6U, /*!< Clear output on compare. */ + kENET_PtpChannelSetCompare = 7U, /*!< Set output on compare. */ + kENET_PtpChannelClearCompareSetOverflow = 10U, /*!< Clear output on compare, set output on overflow. */ + kENET_PtpChannelSetCompareClearOverflow = 11U, /*!< Set output on compare, clear output on overflow. */ + kENET_PtpChannelPulseLowonCompare = 14U, /*!< Pulse output low on compare for one IEEE 1588 clock cycle. */ + kENET_PtpChannelPulseHighonCompare = 15U /*!< Pulse output high on compare for one IEEE 1588 clock cycle. */ +} enet_ptp_timer_channel_mode_t; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! @brief Defines the receive buffer descriptor structure for the little endian system.*/ +typedef struct _enet_rx_bd_struct +{ + uint16_t length; /*!< Buffer descriptor data length. */ + uint16_t control; /*!< Buffer descriptor control and status. */ + uint8_t *buffer; /*!< Data buffer pointer. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint16_t controlExtend0; /*!< Extend buffer descriptor control0. */ + uint16_t controlExtend1; /*!< Extend buffer descriptor control1. */ + uint16_t payloadCheckSum; /*!< Internal payload checksum. */ + uint8_t headerLength; /*!< Header length. */ + uint8_t protocolTyte; /*!< Protocol type. */ + uint16_t reserved0; + uint16_t controlExtend2; /*!< Extend buffer descriptor control2. */ + uint32_t timestamp; /*!< Timestamp. */ + uint16_t reserved1; + uint16_t reserved2; + uint16_t reserved3; + uint16_t reserved4; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +} enet_rx_bd_struct_t; + +/*! @brief Defines the enhanced transmit buffer descriptor structure for the little endian system. */ +typedef struct _enet_tx_bd_struct +{ + uint16_t length; /*!< Buffer descriptor data length. */ + uint16_t control; /*!< Buffer descriptor control and status. */ + uint8_t *buffer; /*!< Data buffer pointer. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint16_t controlExtend0; /*!< Extend buffer descriptor control0. */ + uint16_t controlExtend1; /*!< Extend buffer descriptor control1. */ +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + uint16_t txLaunchTimeLow; /*!< Low 16-bits of transmit launch time. */ + uint16_t txLaunchTimeHigh; /*!< High 16-bits of transmit launch time. */ +#else + uint16_t reserved0; + uint16_t reserved1; +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + uint16_t reserved2; + uint16_t controlExtend2; /*!< Extend buffer descriptor control2. */ + uint32_t timestamp; /*!< Timestamp. */ + uint16_t reserved3; + uint16_t reserved4; + uint16_t reserved5; + uint16_t reserved6; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +} enet_tx_bd_struct_t; + +/*! @brief Defines the ENET data error statistics structure. */ +typedef struct _enet_data_error_stats +{ + uint32_t statsRxLenGreaterErr; /*!< Receive length greater than RCR[MAX_FL]. */ + uint32_t statsRxAlignErr; /*!< Receive non-octet alignment/ */ + uint32_t statsRxFcsErr; /*!< Receive CRC error. */ + uint32_t statsRxOverRunErr; /*!< Receive over run. */ + uint32_t statsRxTruncateErr; /*!< Receive truncate. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint32_t statsRxProtocolChecksumErr; /*!< Receive protocol checksum error. */ + uint32_t statsRxIpHeadChecksumErr; /*!< Receive IP header checksum error. */ + uint32_t statsRxMacErr; /*!< Receive Mac error. */ + uint32_t statsRxPhyErr; /*!< Receive PHY error. */ + uint32_t statsRxCollisionErr; /*!< Receive collision. */ + uint32_t statsTxErr; /*!< The error happen when transmit the frame. */ + uint32_t statsTxFrameErr; /*!< The transmit frame is error. */ + uint32_t statsTxOverFlowErr; /*!< Transmit overflow. */ + uint32_t statsTxLateCollisionErr; /*!< Transmit late collision. */ + uint32_t statsTxExcessCollisionErr; /*!< Transmit excess collision.*/ + uint32_t statsTxUnderFlowErr; /*!< Transmit under flow error. */ + uint32_t statsTxTsErr; /*!< Transmit time stamp error. */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +} enet_data_error_stats_t; + +/*! @brief Defines the Rx frame error structure. */ +typedef struct _enet_rx_frame_error +{ + bool statsRxTruncateErr : 1; /*!< Receive truncate. */ + bool statsRxOverRunErr : 1; /*!< Receive over run. */ + bool statsRxFcsErr : 1; /*!< Receive CRC error. */ + bool : 1; + bool statsRxAlignErr : 1; /*!< Receive non-octet alignment. */ + bool statsRxLenGreaterErr : 1; /*!< Receive length greater than RCR[MAX_FL]. */ + uint32_t : 19; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + bool statsRxCollisionErr : 1; /*!< Receive collision. */ + bool statsRxPhyErr : 1; /*!< Receive PHY error. */ + uint8_t : 4; + bool statsRxMacErr : 1; /*!< Receive Mac error. */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ +} enet_rx_frame_error_t; + +/*! @brief Defines the ENET transfer statistics structure. */ +typedef struct _enet_transfer_stats +{ + uint32_t statsRxFrameCount; /*!< Rx frame number. */ + uint32_t statsRxFrameOk; /*!< Good Rx frame number. */ + uint32_t statsRxCrcErr; /*!< Rx frame number with CRC error. */ + uint32_t statsRxAlignErr; /*!< Rx frame number with alignment error. */ + uint32_t statsRxDropInvalidSFD; /*!< Dropped frame number due to invalid SFD. */ + uint32_t statsRxFifoOverflowErr; /*!< Rx FIFO overflow count. */ + uint32_t statsTxFrameCount; /*!< Tx frame number. */ + uint32_t statsTxFrameOk; /*!< Good Tx frame number. */ + uint32_t statsTxCrcAlignErr; /*!< The transmit frame is error. */ + uint32_t statsTxFifoUnderRunErr; /*!< Tx FIFO underrun count. */ +} enet_transfer_stats_t; + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! @brief Defines the ENET PTP time stamp structure. */ +typedef struct _enet_ptp_time +{ + uint64_t second; /*!< Second. */ + uint32_t nanosecond; /*!< Nanosecond. */ +} enet_ptp_time_t; + +/*! @brief Defines the structure for the ENET PTP message data and timestamp data.*/ +typedef struct _enet_ptp_time_data +{ + uint8_t version; /*!< PTP version. */ + uint8_t sourcePortId[kENET_PtpSrcPortIdLen]; /*!< PTP source port ID. */ + uint16_t sequenceId; /*!< PTP sequence ID. */ + uint8_t messageType; /*!< PTP message type. */ + enet_ptp_time_t timeStamp; /*!< PTP timestamp. */ +} enet_ptp_time_data_t; + +/*! @brief Defines the ENET PTP configuration structure. */ +typedef struct _enet_ptp_config +{ + enet_ptp_timer_channel_t channel; /*!< Used for ERRATA_2579: the PTP 1588 timer channel for time interrupt. */ + uint32_t ptp1588ClockSrc_Hz; /*!< The clock source of the PTP 1588 timer. */ +} enet_ptp_config_t; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! @brief Defines the frame info structure. */ +typedef struct enet_frame_info +{ + void *context; /*!< User specified data */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + bool isTsAvail; /*!< Flag indicates timestamp available status */ + enet_ptp_time_t timeStamp; /*!< Timestamp of frame */ +#endif +} enet_frame_info_t; + +/*! @brief Defines the ENET transmit dirty addresses ring/queue structure. */ +typedef struct _enet_tx_dirty_ring +{ + enet_frame_info_t *txDirtyBase; /*!< Dirty buffer descriptor base address pointer. */ + uint16_t txGenIdx; /*!< tx generate index. */ + uint16_t txConsumIdx; /*!< tx consume index. */ + uint16_t txRingLen; /*!< tx ring length. */ + bool isFull; /*!< tx ring is full flag. */ +} enet_tx_dirty_ring_t; + +/*! @brief Defines the ENET Rx memory buffer alloc function pointer. */ +typedef void *(*enet_rx_alloc_callback_t)(ENET_Type *base, void *userData, uint8_t ringId); + +/*! @brief Defines the ENET Rx memory buffer free function pointer. */ +typedef void (*enet_rx_free_callback_t)(ENET_Type *base, void *buffer, void *userData, uint8_t ringId); + +/*! @brief Defines the receive buffer descriptor configuration structure. + * + * Note that for the internal DMA requirements, the buffers have a corresponding alignment requirements. + * 1. The aligned receive and transmit buffer size must be evenly divisible by ENET_BUFF_ALIGNMENT. + * when the data buffers are in cacheable region when cache is enabled, all those size should be + * aligned to the maximum value of "ENET_BUFF_ALIGNMENT" and the cache line size. + * 2. The aligned transmit and receive buffer descriptor start address must be at + * least 64 bit aligned. However, it's recommended to be evenly divisible by ENET_BUFF_ALIGNMENT. + * buffer descriptors should be put in non-cacheable region when cache is enabled. + * 3. The aligned transmit and receive data buffer start address must be evenly divisible by ENET_BUFF_ALIGNMENT. + * Receive buffers should be continuous with the total size equal to "rxBdNumber * rxBuffSizeAlign". + * Transmit buffers should be continuous with the total size equal to "txBdNumber * txBuffSizeAlign". + * when the data buffers are in cacheable region when cache is enabled, all those size should be + * aligned to the maximum value of "ENET_BUFF_ALIGNMENT" and the cache line size. + */ +typedef struct _enet_buffer_config +{ + uint16_t rxBdNumber; /*!< Receive buffer descriptor number. */ + uint16_t txBdNumber; /*!< Transmit buffer descriptor number. */ + uint16_t rxBuffSizeAlign; /*!< Aligned receive data buffer size. */ + uint16_t txBuffSizeAlign; /*!< Aligned transmit data buffer size. */ + volatile enet_rx_bd_struct_t + *rxBdStartAddrAlign; /*!< Aligned receive buffer descriptor start address: should be non-cacheable. */ + volatile enet_tx_bd_struct_t + *txBdStartAddrAlign; /*!< Aligned transmit buffer descriptor start address: should be non-cacheable. */ + uint8_t *rxBufferAlign; /*!< Receive data buffer start address. */ + uint8_t *txBufferAlign; /*!< Transmit data buffer start address. */ + bool rxMaintainEnable; /*!< Receive buffer cache maintain. */ + bool txMaintainEnable; /*!< Transmit buffer cache maintain. */ + enet_frame_info_t *txFrameInfo; /*!< Transmit frame information start address. */ +} enet_buffer_config_t; + +#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE +/*! @brief Defines the interrupt coalescing configure structure. */ +typedef struct _enet_intcoalesce_config +{ + uint8_t txCoalesceFrameCount[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit interrupt coalescing frame count threshold. */ + uint16_t txCoalesceTimeCount[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit interrupt coalescing timer count threshold. */ + uint8_t rxCoalesceFrameCount[FSL_FEATURE_ENET_QUEUE]; /*!< Receive interrupt coalescing frame count threshold. */ + uint16_t rxCoalesceTimeCount[FSL_FEATURE_ENET_QUEUE]; /*!< Receive interrupt coalescing timer count threshold. */ +} enet_intcoalesce_config_t; +#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */ + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB +/*! @brief Defines the ENET AVB Configure structure. + * + * This is used for to configure the extended ring 1 and ring 2. + * 1. The classification match format is (CMP3 << 12) | (CMP2 << 8) | (CMP1 << 4) | CMP0. + * composed of four 3-bit compared VLAN priority field cmp0~cmp3, cm0 ~ cmp3 are used in parallel. + * + * If CMP1,2,3 are not unused, please set them to the same value as CMP0. + * 2. The idleSlope is used to calculate the Band Width fraction, BW fraction = 1 / (1 + 512/idleSlope). + * For avb configuration, the BW fraction of Class 1 and Class 2 combined must not exceed 0.75. + */ +typedef struct _enet_avb_config +{ + uint16_t rxClassifyMatch[FSL_FEATURE_ENET_QUEUE - 1]; /*!< The classification match value for the ring. */ + enet_idle_slope_t idleSlope[FSL_FEATURE_ENET_QUEUE - 1]; /*!< The idle slope for certian bandwidth fraction. */ +} enet_avb_config_t; +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + +/* Forward declaration of the handle typedef. */ +typedef struct _enet_handle enet_handle_t; + +/*! @brief ENET callback function. */ +typedef void (*enet_callback_t)(ENET_Type *base, + enet_handle_t *handle, +#if FSL_FEATURE_ENET_QUEUE > 1 + uint32_t ringId, +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + enet_event_t event, + enet_frame_info_t *frameInfo, + void *userData); + +/*! @brief Defines the basic configuration structure for the ENET device. + * + * Note: + * 1. macSpecialConfig is used for a special control configuration, A logical OR of + * "enet_special_control_flag_t". For a special configuration for MAC, + * set this parameter to 0. + * 2. txWatermark is used for a cut-through operation. It is in steps of 64 bytes: + * 0/1 - 64 bytes written to TX FIFO before transmission of a frame begins. + * 2 - 128 bytes written to TX FIFO .... + * 3 - 192 bytes written to TX FIFO .... + * The maximum of txWatermark is 0x2F - 4032 bytes written to TX FIFO .... + * txWatermark allows minimizing the transmit latency to set the txWatermark to 0 or 1 + * or for larger bus access latency 3 or larger due to contention for the system bus. + * 3. rxFifoFullThreshold is similar to the txWatermark for cut-through operation in RX. + * It is in 64-bit words. The minimum is ENET_FIFO_MIN_RX_FULL and the maximum is 0xFF. + * If the end of the frame is stored in FIFO and the frame size if smaller than the + * txWatermark, the frame is still transmitted. The rule is the + * same for rxFifoFullThreshold in the receive direction. + * 4. When "kENET_ControlFlowControlEnable" is set in the macSpecialConfig, ensure + * that the pauseDuration, rxFifoEmptyThreshold, and rxFifoStatEmptyThreshold + * are set for flow control enabled case. + * 5. When "kENET_ControlStoreAndFwdDisabled" is set in the macSpecialConfig, ensure + * that the rxFifoFullThreshold and txFifoWatermark are set for store and forward disable. + * 6. The rxAccelerConfig and txAccelerConfig default setting with 0 - accelerator + * are disabled. The "enet_tx_accelerator_t" and "enet_rx_accelerator_t" are + * recommended to be used to enable the transmit and receive accelerator. + * After the accelerators are enabled, the store and forward feature should be enabled. + * As a result, kENET_ControlStoreAndFwdDisabled should not be set. + * 7. The intCoalesceCfg can be used in the rx or tx enabled cases to decrese the CPU loading. + */ +typedef struct _enet_config +{ + uint32_t macSpecialConfig; /*!< Mac special configuration. A logical OR of "enet_special_control_flag_t". */ + uint32_t interrupt; /*!< Mac interrupt source. A logical OR of "enet_interrupt_enable_t". */ + uint16_t rxMaxFrameLen; /*!< Receive maximum frame length. */ + enet_mii_mode_t miiMode; /*!< MII mode. */ + enet_mii_speed_t miiSpeed; /*!< MII Speed. */ + enet_mii_duplex_t miiDuplex; /*!< MII duplex. */ + uint8_t rxAccelerConfig; /*!< Receive accelerator, A logical OR of "enet_rx_accelerator_t". */ + uint8_t txAccelerConfig; /*!< Transmit accelerator, A logical OR of "enet_rx_accelerator_t". */ + uint16_t pauseDuration; /*!< For flow control enabled case: Pause duration. */ + uint8_t rxFifoEmptyThreshold; /*!< For flow control enabled case: when RX FIFO level reaches this value, + it makes MAC generate XOFF pause frame. */ +#if defined(FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD) && FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD + uint8_t rxFifoStatEmptyThreshold; /*!< For flow control enabled case: number of frames in the receive FIFO, + independent of size, that can be accept. If the limit is reached, reception + continues and a pause frame is triggered. */ +#endif /* FSL_FEATURE_ENET_HAS_RECEIVE_STATUS_THRESHOLD */ + uint8_t rxFifoFullThreshold; /*!< For store and forward disable case, the data required in RX FIFO to notify + the MAC receive ready status. */ + uint8_t txFifoWatermark; /*!< For store and forward disable case, the data required in TX FIFO + before a frame transmit start. */ +#if defined(FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE) && FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE + enet_intcoalesce_config_t *intCoalesceCfg; /*!< If the interrupt coalsecence is not required in the ring n(0,1,2), + please set to NULL. */ +#endif /* FSL_FEATURE_ENET_HAS_INTERRUPT_COALESCE */ + uint8_t ringNum; /*!< Number of used rings. default with 1 -- single ring. */ + enet_rx_alloc_callback_t rxBuffAlloc; /*!< Callback function to alloc memory, must be provided for zero-copy Rx. */ + enet_rx_free_callback_t rxBuffFree; /*!< Callback function to free memory, must be provided for zero-copy Rx. */ + enet_callback_t callback; /*!< General callback function. */ + void *userData; /*!< Callback function parameter.*/ +} enet_config_t; + +/*! @brief Defines the ENET transmit buffer descriptor ring/queue structure. */ +typedef struct _enet_tx_bd_ring +{ + volatile enet_tx_bd_struct_t *txBdBase; /*!< Buffer descriptor base address pointer. */ + uint16_t txGenIdx; /*!< The current available transmit buffer descriptor pointer. */ + uint16_t txConsumIdx; /*!< Transmit consume index. */ + volatile uint16_t txDescUsed; /*!< Transmit descriptor used number. */ + uint16_t txRingLen; /*!< Transmit ring length. */ +} enet_tx_bd_ring_t; + +/*! @brief Defines the ENET receive buffer descriptor ring/queue structure. */ +typedef struct _enet_rx_bd_ring +{ + volatile enet_rx_bd_struct_t *rxBdBase; /*!< Buffer descriptor base address pointer. */ + uint16_t rxGenIdx; /*!< The current available receive buffer descriptor pointer. */ + uint16_t rxRingLen; /*!< Receive ring length. */ +} enet_rx_bd_ring_t; + +/*! @brief Defines the ENET handler structure. */ +struct _enet_handle +{ + enet_rx_bd_ring_t rxBdRing[FSL_FEATURE_ENET_QUEUE]; /*!< Receive buffer descriptor. */ + enet_tx_bd_ring_t txBdRing[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit buffer descriptor. */ + uint16_t rxBuffSizeAlign[FSL_FEATURE_ENET_QUEUE]; /*!< Receive buffer size alignment. */ + uint16_t txBuffSizeAlign[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit buffer size alignment. */ + bool rxMaintainEnable[FSL_FEATURE_ENET_QUEUE]; /*!< Receive buffer cache maintain. */ + bool txMaintainEnable[FSL_FEATURE_ENET_QUEUE]; /*!< Transmit buffer cache maintain. */ + uint8_t ringNum; /*!< Number of used rings. */ + enet_callback_t callback; /*!< Callback function. */ + void *userData; /*!< Callback function parameter.*/ + enet_tx_dirty_ring_t txDirtyRing[FSL_FEATURE_ENET_QUEUE]; /*!< Ring to store tx frame information.*/ + bool txReclaimEnable[FSL_FEATURE_ENET_QUEUE]; /*!< Tx reclaim enable flag.*/ + enet_rx_alloc_callback_t rxBuffAlloc; /*!< Callback function to alloc memory for zero copy Rx. */ + enet_rx_free_callback_t rxBuffFree; /*!< Callback function to free memory for zero copy Rx. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + volatile enet_tx_bd_struct_t + *txBdDirtyStatic[FSL_FEATURE_ENET_QUEUE]; /*!< The dirty transmit buffer descriptor for error static update. */ + uint64_t msTimerSecond; /*!< The second for Master PTP timer. */ +#endif + uint8_t multicastCount[64]; /*!< Multicast collisions counter */ +#if defined(FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID) && FSL_FEATURE_ENET_TIMESTAMP_CAPTURE_BIT_INVALID + uint32_t enetClock; /*!< The clock of enet peripheral, to caculate core cycles for PTP timestamp.*/ + uint32_t tsDelayCount; /*!< The count of core cycles for PTP timestamp capture delay.*/ +#endif +}; + +typedef struct _enet_buffer_struct +{ + void *buffer; /*!< The buffer store the whole or partial frame. */ + uint16_t length; /*!< The byte length of this buffer. */ +} enet_buffer_struct_t; + +typedef struct _enet_rx_frame_attribute_struct +{ + bool promiscuous; /*!< This frame is received because of promiscuous mode. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint32_t timestamp; /*!< The nanosecond part timestamp of this Rx frame. */ +#endif +} enet_rx_frame_attribute_t; + +typedef struct _enet_rx_frame_struct +{ + enet_buffer_struct_t *rxBuffArray; /*!< Rx frame buffer structure. */ + uint16_t totLen; /*!< Rx frame total length. */ + enet_rx_frame_attribute_t rxAttribute; /*!< Rx frame attribute structure. */ + enet_rx_frame_error_t rxFrameError; /*!< Rx frame error. */ +} enet_rx_frame_struct_t; + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +typedef struct _enet_tx_config_struct +{ + bool intEnable : 1; + bool tsEnable : 1; + bool autoProtocolChecksum : 1; + bool autoIPChecksum : 1; + uint8_t AVBFrameType : 4; /*!< AVB class type. */ + bool tltEnable : 1; /*!< Transmit launch time enable. */ + uint16_t tltLow; /*!< Specifies when frame can be transmitted. */ + uint16_t tltHigh; /*!< Specifies when frame can be transmitted. */ +} enet_tx_config_struct_t; +#endif + +typedef struct _enet_tx_frame_struct +{ + enet_buffer_struct_t *txBuffArray; /*!< Tx frame buffer structure. */ + uint32_t txBuffNum; /*!< Buffer number of this Tx frame. */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + enet_tx_config_struct_t txConfig; /*!< Tx extra configuation. */ +#endif + void *context; /*!< Driver reclaims and gives it in Tx over callback, usually store network packet header. */ +} enet_tx_frame_struct_t; + +/*! @brief Define interrupt IRQ handler. */ +#if FSL_FEATURE_ENET_QUEUE > 1 +typedef void (*enet_isr_ring_t)(ENET_Type *base, enet_handle_t *handle, uint32_t ringId); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +typedef void (*enet_isr_t)(ENET_Type *base, enet_handle_t *handle); + +/*! @brief Pointers to enet clocks for each instance. */ +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +extern const clock_ip_name_t s_enetClock[]; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Get the ENET instance from peripheral base address. + * + * @param base ENET peripheral base address. + * @return ENET instance. + */ +uint32_t ENET_GetInstance(ENET_Type *base); + +/*! + * @name Initialization and De-initialization + * @{ + */ + +/*! + * @brief Gets the ENET default configuration structure. + * + * The purpose of this API is to get the default ENET MAC controller + * configure structure for ENET_Init(). User may use the initialized + * structure unchanged in ENET_Init(), or modify some fields of the + * structure before calling ENET_Init(). + * Example: + @code + enet_config_t config; + ENET_GetDefaultConfig(&config); + @endcode + * @param config The ENET mac controller configuration structure pointer. + */ +void ENET_GetDefaultConfig(enet_config_t *config); + +/*! + * @brief Initializes the ENET module. + * + * This function initializes the module with the ENET configuration. + * @note ENET has two buffer descriptors legacy buffer descriptors and + * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To + * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor + * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure() + * to configure the 1588 feature and related buffers after calling ENET_Up(). + * + * @param base ENET peripheral base address. + * @param handle ENET handler pointer. + * @param config ENET mac configuration structure pointer. + * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * @param bufferConfig ENET buffer configuration structure pointer. + * The buffer configuration should be prepared for ENET Initialization. + * It is the start address of "ringNum" enet_buffer_config structures. + * To support added multi-ring features in some soc and compatible with the previous + * enet driver version. For single ring supported, this bufferConfig is a buffer + * configure structure pointer, for multi-ring supported and used case, this bufferConfig + * pointer should be a buffer configure structure array pointer. + * @param macAddr ENET mac address of Ethernet device. This MAC address should be + * provided. + * @param srcClock_Hz The internal module clock source for MII clock. + * @retval kStatus_Success Succeed to initialize the ethernet driver. + * @retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough. + * + */ +status_t ENET_Up(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz); + +/*! + * @brief Initializes the ENET module. + * + * This function ungates the module clock and initializes it with the ENET configuration. + * @note ENET has two buffer descriptors legacy buffer descriptors and + * enhanced IEEE 1588 buffer descriptors. The legacy descriptor is used by default. To + * use the IEEE 1588 feature, use the enhanced IEEE 1588 buffer descriptor + * by defining "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" and calling ENET_Ptp1588Configure() + * to configure the 1588 feature and related buffers after calling ENET_Init(). + * + * @param base ENET peripheral base address. + * @param handle ENET handler pointer. + * @param config ENET mac configuration structure pointer. + * The "enet_config_t" type mac configuration return from ENET_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * @param bufferConfig ENET buffer configuration structure pointer. + * The buffer configuration should be prepared for ENET Initialization. + * It is the start address of "ringNum" enet_buffer_config structures. + * To support added multi-ring features in some soc and compatible with the previous + * enet driver version. For single ring supported, this bufferConfig is a buffer + * configure structure pointer, for multi-ring supported and used case, this bufferConfig + * pointer should be a buffer configure structure array pointer. + * @param macAddr ENET mac address of Ethernet device. This MAC address should be + * provided. + * @param srcClock_Hz The internal module clock source for MII clock. + * @retval kStatus_Success Succeed to initialize the ethernet driver. + * @retval kStatus_ENET_InitMemoryFail Init fails since buffer memory is not enough. + */ +status_t ENET_Init(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig, + uint8_t *macAddr, + uint32_t srcClock_Hz); + +/*! + * @brief Stops the ENET module. + + * This function disables the ENET module. + * + * @param base ENET peripheral base address. + */ +void ENET_Down(ENET_Type *base); + +/*! + * @brief Deinitializes the ENET module. + + * This function gates the module clock, clears ENET interrupts, and disables the ENET module. + * + * @param base ENET peripheral base address. + */ +void ENET_Deinit(ENET_Type *base); + +/*! + * @brief Resets the ENET module. + * + * This function restores the ENET module to reset state. + * Note that this function sets all registers to + * reset state. As a result, the ENET module can't work after calling this function. + * + * @param base ENET peripheral base address. + */ +static inline void ENET_Reset(ENET_Type *base) +{ + base->ECR |= ENET_ECR_RESET_MASK; +} + +/* @} */ + +/*! + * @name MII interface operation + * @{ + */ + +/*! + * @brief Sets the ENET MII speed and duplex. + * + * This API is provided to dynamically change the speed and dulpex for MAC. + * + * @param base ENET peripheral base address. + * @param speed The speed of the RMII mode. + * @param duplex The duplex of the RMII mode. + */ +void ENET_SetMII(ENET_Type *base, enet_mii_speed_t speed, enet_mii_duplex_t duplex); + +/*! + * @brief Sets the ENET SMI(serial management interface)- MII management interface. + * + * @param base ENET peripheral base address. + * @param srcClock_Hz This is the ENET module clock frequency. See clock distribution. + * @param isPreambleDisabled The preamble disable flag. + * - true Enables the preamble. + * - false Disables the preamble. + */ +void ENET_SetSMI(ENET_Type *base, uint32_t srcClock_Hz, bool isPreambleDisabled); + +/*! + * @brief Gets the ENET SMI- MII management interface configuration. + * + * This API is used to get the SMI configuration to check whether the MII management + * interface has been set. + * + * @param base ENET peripheral base address. + * @return The SMI setup status true or false. + */ +static inline bool ENET_GetSMI(ENET_Type *base) +{ + return (0U != (base->MSCR & 0x7EU)); +} + +/*! + * @brief Reads data from the PHY register through an SMI interface. + * + * @param base ENET peripheral base address. + * @return The data read from PHY + */ +static inline uint32_t ENET_ReadSMIData(ENET_Type *base) +{ + return (uint32_t)((base->MMFR & ENET_MMFR_DATA_MASK) >> ENET_MMFR_DATA_SHIFT); +} + +/*! + * @brief Starts an SMI (Serial Management Interface) read command. + * + * Used for standard IEEE802.3 MDIO Clause 22 format. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. Range from 0 ~ 31. + * @param operation The read operation. + */ +void ENET_StartSMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_read_t operation); + +/*! + * @brief Starts an SMI write command. + * + * Used for standard IEEE802.3 MDIO Clause 22 format. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. Range from 0 ~ 31. + * @param operation The write operation. + * @param data The data written to PHY. + */ +void ENET_StartSMIWrite(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, enet_mii_write_t operation, uint32_t data); + +#if defined(FSL_FEATURE_ENET_HAS_EXTEND_MDIO) && FSL_FEATURE_ENET_HAS_EXTEND_MDIO +/*! + * @brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write register command. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIWriteReg(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg); + +/*! + * @brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI write data command. + * + * After writing MMFR register, we need to check whether the transmission is over. + * This is an example for whole precedure of clause 45 MDIO write. + * @code + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteData(base, phyAddr, phyReg, data); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * @endcode + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + * @param data The data written to PHY. + */ +void ENET_StartExtC45SMIWriteData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data); + +/*! + * @brief Starts the extended IEEE802.3 Clause 45 MDIO format SMI read data command. + * + * After writing MMFR register, we need to check whether the transmission is over. + * This is an example for whole precedure of clause 45 MDIO read. + * @code + * uint32_t data; + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIWriteReg(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * ENET_StartExtC45SMIReadData(base, phyAddr, phyReg); + * while ((ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) == 0U) + * { + * } + * ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + * data = ENET_ReadSMIData(base); + * @endcode + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. For MDIO IEEE802.3 Clause 45, + * the phyReg is a 21-bits combination of the devaddr (5 bits device address) + * and the regAddr (16 bits phy register): phyReg = (devaddr << 16) | regAddr. + */ +void ENET_StartExtC45SMIReadData(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg); +#endif /* FSL_FEATURE_ENET_HAS_EXTEND_MDIO */ + +#if ((defined(FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY) || \ + (defined(FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY)) +/*! + * @brief Control the usage of the delayed tx/rx RGMII clock. + * + * @param base ENET peripheral base address. + * @param txEnabled Enable or disable to generate the delayed version of RGMII_TXC. + * @param rxEnabled Enable or disable to use the delayed version of RGMII_RXC. + */ +static inline void ENET_SetRGMIIClockDelay(ENET_Type *base, bool txEnabled, bool rxEnabled) +{ + uint32_t ecrReg = base->ECR; + +#if defined(FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY + /* Set for transmit clock delay. */ + if (txEnabled) + { + ecrReg |= ENET_ECR_TXC_DLY_MASK; + } + else + { + ecrReg &= ~ENET_ECR_TXC_DLY_MASK; + } +#endif /* FSL_FEATURE_ENET_HAS_RGMII_TXC_DELAY */ + +#if defined(FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY) && FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY + /* Set for receive clock delay. */ + if (rxEnabled) + { + ecrReg |= ENET_ECR_RXC_DLY_MASK; + } + else + { + ecrReg &= ~ENET_ECR_RXC_DLY_MASK; + } +#endif /* FSL_FEATURE_ENET_HAS_RGMII_RXC_DELAY */ + base->ECR = ecrReg; +} +#endif + +/* @} */ + +/*! + * @name MAC Address Filter + * @{ + */ + +/*! + * @brief Sets the ENET module Mac address. + * + * @param base ENET peripheral base address. + * @param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + */ +void ENET_SetMacAddr(ENET_Type *base, uint8_t *macAddr); + +/*! + * @brief Gets the ENET module Mac address. + * + * @param base ENET peripheral base address. + * @param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + */ +void ENET_GetMacAddr(ENET_Type *base, uint8_t *macAddr); + +/*! + * @brief Adds the ENET device to a multicast group. + * + * @param base ENET peripheral base address. + * @param address The six-byte multicast group address which is provided by application. + */ +void ENET_AddMulticastGroup(ENET_Type *base, uint8_t *address); + +/*! + * @brief Moves the ENET device from a multicast group. + * + * @param base ENET peripheral base address. + * @param address The six-byte multicast group address which is provided by application. + */ +void ENET_LeaveMulticastGroup(ENET_Type *base, uint8_t *address); + +/* @} */ + +/*! + * @name Other basic operation + * @{ + */ + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB +/*! + * @brief Sets the ENET AVB feature. + * + * ENET AVB feature configuration, set the Receive classification match and transmit + * bandwidth. This API is called when the AVB feature is required. + * + * Note: The AVB frames transmission scheme is credit-based tx scheme and it's only supported + * with the Enhanced buffer descriptors. so the AVB configuration should only done with + * Enhanced buffer descriptor. so when the AVB feature is required, please make sure the + * the "ENET_ENHANCEDBUFFERDESCRIPTOR_MODE" is defined. + * + * @param base ENET peripheral base address. + * @param handle ENET handler pointer. + * @param config The ENET AVB feature configuration structure. + */ +void ENET_AVBConfigure(ENET_Type *base, enet_handle_t *handle, const enet_avb_config_t *config); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! + * @brief Activates frame reception for multiple rings. + * + * This function is to active the enet read process. + * @note This must be called after the MAC configuration and + * state are ready. It must be called after the ENET_Init(). + * This should be called when the frame reception is required. + * + * @param base ENET peripheral base address. + */ +static inline void ENET_ActiveRead(ENET_Type *base) +{ + base->RDAR = ENET_RDAR_RDAR_MASK; +#if FSL_FEATURE_ENET_QUEUE > 1 + if (FSL_FEATURE_ENET_INSTANCE_QUEUEn(base) > 1) + { + base->RDAR1 = ENET_RDAR1_RDAR_MASK; + base->RDAR2 = ENET_RDAR2_RDAR_MASK; + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +} + +/*! + * @brief Enables/disables the MAC to enter sleep mode. + * This function is used to set the MAC enter sleep mode. + * When entering sleep mode, the magic frame wakeup interrupt should be enabled + * to wake up MAC from the sleep mode and reset it to normal mode. + * + * @param base ENET peripheral base address. + * @param enable True enable sleep mode, false disable sleep mode. + */ +static inline void ENET_EnableSleepMode(ENET_Type *base, bool enable) +{ + if (enable) + { + /* When this field is set, MAC enters sleep mode. */ + base->ECR |= ENET_ECR_SLEEP_MASK | ENET_ECR_MAGICEN_MASK; + } + else + { /* MAC exits sleep mode. */ + base->ECR &= ~(ENET_ECR_SLEEP_MASK | ENET_ECR_MAGICEN_MASK); + } +} + +/*! + * @brief Gets ENET transmit and receive accelerator functions from MAC controller. + * + * @param base ENET peripheral base address. + * @param txAccelOption The transmit accelerator option. The "enet_tx_accelerator_t" is + * recommended to be used to as the mask to get the exact the accelerator option. + * @param rxAccelOption The receive accelerator option. The "enet_rx_accelerator_t" is + * recommended to be used to as the mask to get the exact the accelerator option. + */ +static inline void ENET_GetAccelFunction(ENET_Type *base, uint32_t *txAccelOption, uint32_t *rxAccelOption) +{ + assert(txAccelOption != NULL); + assert(txAccelOption != NULL); + + *txAccelOption = base->TACC; + *rxAccelOption = base->RACC; +} + +/* @} */ + +/*! + * @name Interrupts. + * @{ + */ + +/*! + * @brief Enables the ENET interrupt. + * + * This function enables the ENET interrupt according to the provided mask. The mask + * is a logical OR of enumeration members. See ::enet_interrupt_enable_t. + * For example, to enable the TX frame interrupt and RX frame interrupt, do the following. + * @code + * ENET_EnableInterrupts(ENET, kENET_TxFrameInterrupt | kENET_RxFrameInterrupt); + * @endcode + * + * @param base ENET peripheral base address. + * @param mask ENET interrupts to enable. This is a logical OR of the + * enumeration ::enet_interrupt_enable_t. + */ +static inline void ENET_EnableInterrupts(ENET_Type *base, uint32_t mask) +{ + base->EIMR |= mask; +} + +/*! + * @brief Disables the ENET interrupt. + * + * This function disables the ENET interrupts according to the provided mask. The mask + * is a logical OR of enumeration members. See ::enet_interrupt_enable_t. + * For example, to disable the TX frame interrupt and RX frame interrupt, do the following. + * @code + * ENET_DisableInterrupts(ENET, kENET_TxFrameInterrupt | kENET_RxFrameInterrupt); + * @endcode + * + * @param base ENET peripheral base address. + * @param mask ENET interrupts to disable. This is a logical OR of the + * enumeration ::enet_interrupt_enable_t. + */ +static inline void ENET_DisableInterrupts(ENET_Type *base, uint32_t mask) +{ + base->EIMR &= ~mask; +} + +/*! + * @brief Gets the ENET interrupt status flag. + * + * @param base ENET peripheral base address. + * @return The event status of the interrupt source. This is the logical OR of members + * of the enumeration ::enet_interrupt_enable_t. + */ +static inline uint32_t ENET_GetInterruptStatus(ENET_Type *base) +{ + return base->EIR; +} + +/*! + * @brief Clears the ENET interrupt events status flag. + * + * This function clears enabled ENET interrupts according to the provided mask. The mask + * is a logical OR of enumeration members. See the ::enet_interrupt_enable_t. + * For example, to clear the TX frame interrupt and RX frame interrupt, do the following. + * @code + * ENET_ClearInterruptStatus(ENET, kENET_TxFrameInterrupt | kENET_RxFrameInterrupt); + * @endcode + * + * @param base ENET peripheral base address. + * @param mask ENET interrupt source to be cleared. + * This is the logical OR of members of the enumeration ::enet_interrupt_enable_t. + */ +static inline void ENET_ClearInterruptStatus(ENET_Type *base, uint32_t mask) +{ + base->EIR = mask; +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * @brief Set the second level Rx IRQ handler + * + * @param base ENET peripheral base address. + * @param ISRHandler The handler to install. + */ +void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler); + +/*! + * @brief Set the second level Tx IRQ handler + * + * @param base ENET peripheral base address. + * @param ISRHandler The handler to install. + */ +void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_ring_t ISRHandler); + +#else +/*! + * @brief Set the second level Rx IRQ handler + * + * @param base ENET peripheral base address. + * @param ISRHandler The handler to install. + */ +void ENET_SetRxISRHandler(ENET_Type *base, enet_isr_t ISRHandler); + +/*! + * @brief Set the second level Tx IRQ handler + * + * @param base ENET peripheral base address. + * @param ISRHandler The handler to install. + */ +void ENET_SetTxISRHandler(ENET_Type *base, enet_isr_t ISRHandler); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +/*! + * @brief Set the second level Err IRQ handler + * + * @param base ENET peripheral base address. + * @param ISRHandler The handler to install. + */ +void ENET_SetErrISRHandler(ENET_Type *base, enet_isr_t ISRHandler); + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * @brief Set the second level Ts IRQ handler + * + * @param ISRHandler The handler to install. + */ +void ENET_SetTsISRHandler(ENET_Type *base, enet_isr_t ISRHandler); + +/*! + * @brief Set the second level 1588 Timer IRQ handler + * + * @param ISRHandler The handler to install. + */ +void ENET_Set1588TimerISRHandler(ENET_Type *base, enet_isr_t ISRHandler); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/* @} */ + +/*! + * @name Transactional operation + * @{ + */ + +/*! + * @brief Sets the callback function. + * @deprecated Do not use this function. It has been superceded by the config param in @ref ENET_Init. + * This API is provided for the application callback required case when ENET + * interrupt is enabled. This API should be called after calling ENET_Init. + * + * @param handle ENET handler pointer. Should be provided by application. + * @param callback The ENET callback function. + * @param userData The callback function parameter. + */ +void ENET_SetCallback(enet_handle_t *handle, enet_callback_t callback, void *userData); + +/*! + * @brief Gets the error statistics of a received frame for ENET specified ring. + * + * This API must be called after the ENET_GetRxFrameSize and before the ENET_ReadFrame(). + * If the ENET_GetRxFrameSize returns kStatus_ENET_RxFrameError, + * the ENET_GetRxErrBeforeReadFrame can be used to get the exact error statistics. + * This is an example. + * @code + * status = ENET_GetRxFrameSize(&g_handle, &length, 0); + * if (status == kStatus_ENET_RxFrameError) + * { + * Comments: Get the error information of the received frame. + * ENET_GetRxErrBeforeReadFrame(&g_handle, &eErrStatic, 0); + * Comments: update the receive buffer. + * ENET_ReadFrame(EXAMPLE_ENET, &g_handle, NULL, 0); + * } + * @endcode + * @param handle The ENET handler structure pointer. This is the same handler pointer used in the ENET_Init. + * @param eErrorStatic The error statistics structure pointer. + * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + */ +void ENET_GetRxErrBeforeReadFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId); + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * @brief Gets the ENET transmit frame statistics after the data send for specified ring. + * + * This interface gets the error statistics of the transmit frame. + * Because the error information is reported by the uDMA after the data delivery, this interface + * should be called after the data transmit API. It is recommended to call this function on + * transmit interrupt handler. After calling the ENET_SendFrame, the + * transmit interrupt notifies the transmit completion. + * + * @param handle The PTP handler pointer. This is the same handler pointer used in the ENET_Init. + * @param eErrorStatic The error statistics structure pointer. + * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + * @return The execute status. + */ +status_t ENET_GetTxErrAfterSendFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic, uint8_t ringId); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/*! + * @brief Gets statistical data in transfer. + * + * @param base ENET peripheral base address. + * @param statistics The statistics structure pointer. + */ +void ENET_GetStatistics(ENET_Type *base, enet_transfer_stats_t *statistics); + +/*! + * @brief Gets the size of the read frame for specified ring. + * + * This function gets a received frame size from the ENET buffer descriptors. + * @note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS. + * After calling ENET_GetRxFrameSize, ENET_ReadFrame() should be called to receive frame and update the BD + * if the result is not "kStatus_ENET_RxFrameEmpty". + * + * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * @param length The length of the valid frame received. + * @param ringId The ring index or ring number. + * @retval kStatus_ENET_RxFrameEmpty No frame received. Should not call ENET_ReadFrame to read frame. + * @retval kStatus_ENET_RxFrameError Data error happens. ENET_ReadFrame should be called with NULL data + * and NULL length to update the receive buffers. + * @retval kStatus_Success Receive a frame Successfully then the ENET_ReadFrame + * should be called with the right data buffer and the captured data length input. + */ +status_t ENET_GetRxFrameSize(enet_handle_t *handle, uint32_t *length, uint8_t ringId); + +/*! + * @brief Reads a frame from the ENET device. + * This function reads a frame (both the data and the length) from the ENET buffer descriptors. + * User can get timestamp through ts pointer if the ts is not NULL. + * @note It doesn't store the timestamp in the receive timestamp queue. + * The ENET_GetRxFrameSize should be used to get the size of the prepared data buffer. + * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer + * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time + * consumption. + * This is an example: + * @code + * uint32_t length; + * enet_handle_t g_handle; + * Comments: Get the received frame size firstly. + * status = ENET_GetRxFrameSize(&g_handle, &length, 0); + * if (length != 0) + * { + * Comments: Allocate memory here with the size of "length" + * uint8_t *data = memory allocate interface; + * if (!data) + * { + * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL); + * Comments: Add the console warning log. + * } + * else + * { + * status = ENET_ReadFrame(ENET, &g_handle, data, length, 0, NULL); + * Comments: Call stack input API to deliver the data to stack + * } + * } + * else if (status == kStatus_ENET_RxFrameError) + * { + * Comments: Update the received buffer when a error frame is received. + * ENET_ReadFrame(ENET, &g_handle, NULL, 0, 0, NULL); + * } + * @endcode + * @param base ENET peripheral base address. + * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * @param data The data buffer provided by user to store the frame which memory size should be at least "length". + * @param length The size of the data buffer which is still the length of the received frame. + * @param ringId The ring index or ring number. + * @param ts The timestamp address to store received timestamp. + * @return The execute status, successful or failure. + */ +status_t ENET_ReadFrame( + ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint8_t ringId, uint32_t *ts); + +/*! + * @brief Transmits an ENET frame for specified ring. + * @note The CRC is automatically appended to the data. Input the data to send without the CRC. + * This API uses memcpy to copy data from DMA buffer to application buffer, 4 bytes aligned data buffer + * in 32 bits platforms provided by user may let compiler use optimization instruction to reduce time + * consumption. + * + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param data The data buffer provided by user to send. + * @param length The length of the data to send. + * @param ringId The ring index or ring number. + * @param tsFlag Timestamp enable flag. + * @param context Used by user to handle some events after transmit over. + * @retval kStatus_Success Send frame succeed. + * @retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission. + * The transmit busy happens when the data send rate is over the MAC capacity. + * The waiting mechanism is recommended to be added after each call return with + * kStatus_ENET_TxFrameBusy. + */ +status_t ENET_SendFrame(ENET_Type *base, + enet_handle_t *handle, + const uint8_t *data, + uint32_t length, + uint8_t ringId, + bool tsFlag, + void *context); + +/*! + * @brief Enable or disable tx descriptors reclaim mechanism. + * @note This function must be called when no pending send frame action. + * Set enable if you want to reclaim context or timestamp in interrupt. + * + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param isEnable Enable or disable flag. + * @param ringId The ring index or ring number. + * @retval kStatus_Success Succeed to enable/disable Tx reclaim. + * @retval kStatus_Fail Fail to enable/disable Tx reclaim. + */ +status_t ENET_SetTxReclaim(enet_handle_t *handle, bool isEnable, uint8_t ringId); + +/*! + * @brief Reclaim tx descriptors. + * This function is used to update the tx descriptor status and + * store the tx timestamp when the 1588 feature is enabled. + * This is called by the transmit interupt IRQ handler after the + * complete of a frame transmission. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param ringId The ring index or ring number. + */ +void ENET_ReclaimTxDescriptor(ENET_Type *base, enet_handle_t *handle, uint8_t ringId); + +/*! + * @brief Get a receive buffer pointer of the ENET device for specified ring. + * @deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame. + * + * This function can get the data address which stores frame. Then can analyze these data directly without doing any + * memory copy. When the frame locates in multiple BD buffer, need to repeat calling this function until isLastBuff=true + * (need to store the temp buf pointer everytime call this function). After finishing the analysis of this frame, + * call ENET_ReleaseRxBuffer to release rxbuff memory to DMA. + * This is an example: + * @code + * uint32_t length; + * uint8_t *buf = NULL; + * uint32_t data_len = 0; + * bool isLastBuff = false; + * enet_handle_t g_handle; + * status_t status; + * status = ENET_GetRxFrameSize(&g_handle, &length, 0); + * if (length != 0) + * { + * ENET_GetRxBuffer(EXAMPLE_ENET, &g_handle, &buf, &data_len, 0, &isLastBuff, NULL); + * ENET_ReleaseRxBuffer(EXAMPLE_ENET, &g_handle, buf, 0); + * } + * @endcode + * @param base ENET peripheral base address. + * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * @param buffer The data buffer pointer to store the frame. + * @param length The size of the data buffer. If isLastBuff=false, it represents data length of this buffer. If + * isLastBuff=true, it represents data length of total frame. + * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + * @param isLastBuff The flag represents whether this buffer is the last buffer to store frame. + * @param ts The 1588 timestamp value, vaild in last buffer. + * @retval kStatus_Success Get receive buffer succeed. + * @retval kStatus_ENET_RxFrameFail Get receive buffer fails, it's owned by application, should wait app to release this + * buffer. + */ +status_t ENET_GetRxBuffer(ENET_Type *base, + enet_handle_t *handle, + void **buffer, + uint32_t *length, + uint8_t ringId, + bool *isLastBuff, + uint32_t *ts); + +/*! + * @brief Release receive buffer descriptor to DMA. + * @deprecated Do not use this function. It has been superseded by @ref ENET_GetRxFrame. + * + * This function can release specified BD owned by application, meanwhile it may rearrange the BD to let the no-owned + * BDs always in back of the index of DMA transfer. So for the situation that releasing order is not same as the getting + * order, the rearrangement makes all ready BDs can be used by DMA. + * @note This function can't be interrupted by ENET_GetRxBuffer, so in application must make sure ENET_GetRxBuffer is + * called before or after this function. And this function itself isn't thread safe due to BD content exchanging. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_Init. + * @param buffer The buffer address to store frame, using it to find the correspond BD and release it. + * @param ringId The ring index, range from 0 ~ (FSL_FEATURE_ENET_INSTANCE_QUEUEn(x) - 1). + */ +void ENET_ReleaseRxBuffer(ENET_Type *base, enet_handle_t *handle, void *buffer, uint8_t ringId); + +/*! + * @brief Receives one frame in specified BD ring with zero copy. + * + * This function will use the user-defined allocate and free callback. Every time application gets one frame through + * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application. + * @note This function will drop current frame and update related BDs as available for DMA if new buffers allocating + * fails. Application must provide a memory pool including at least BD number + 1 buffers to make this function work + * normally. If user calls this function in Rx interrupt handler, be careful that this function makes Rx BD ready with + * allocating new buffer(normal) or updating current BD(out of memory). If there's always new Rx frame input, Rx + * interrupt will be triggered forever. Application need to disable Rx interrupt according to specific design in this + * case. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param rxFrame The received frame information structure provided by user. + * @param ringId The ring index or ring number. + * @retval kStatus_Success Succeed to get one frame and allocate new memory for Rx buffer. + * @retval kStatus_ENET_RxFrameEmpty There's no Rx frame in the BD. + * @retval kStatus_ENET_RxFrameError There's issue in this receiving. + * @retval kStatus_ENET_RxFrameDrop There's no new buffer memory for BD, drop this frame. + */ +status_t ENET_GetRxFrame(ENET_Type *base, enet_handle_t *handle, enet_rx_frame_struct_t *rxFrame, uint8_t ringId); + +/*! + * @brief Sends one frame in specified BD ring with zero copy. + * + * This function supports scattered buffer transmit, user needs to provide the buffer array. + * @note Tx reclaim should be enabled to ensure the Tx buffer ownership can be given back to + * application after Tx is over. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param txFrame The Tx frame structure. + * @param ringId The ring index or ring number. + * @retval kStatus_Success Succeed to send one frame. + * @retval kStatus_ENET_TxFrameBusy The BD is not ready for Tx or the reclaim operation still not finishs. + * @retval kStatus_ENET_TxFrameOverLen The Tx frame length is over max ethernet frame length. + */ +status_t ENET_StartTxFrame(ENET_Type *base, enet_handle_t *handle, enet_tx_frame_struct_t *txFrame, uint8_t ringId); + +/*! + * @brief Transmits an ENET frame for specified ring with zero-copy. + * @deprecated Do not use this function. It has been superseded by @ref ENET_StartTxFrame. + * @note The CRC is automatically appended to the data. Input the data + * to send without the CRC. The frame must store in continuous memory + * and need to check the buffer start address alignment based on your + * device, otherwise it has issue or can't get highest DMA transmit speed. + * + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param data The data buffer provided by user to send. + * @param length The length of the data to send. + * @param ringId The ring index or ring number. + * @param tsFlag Timestamp enable flag. + * @param context Used by user to handle some events after transmit over. + * @retval kStatus_Success Send frame succeed. + * @retval kStatus_ENET_TxFrameBusy Transmit buffer descriptor is busy under transmission. + * The transmit busy happens when the data send rate is over the MAC capacity. + * The waiting mechanism is recommended to be added after each call return with + * kStatus_ENET_TxFrameBusy. + */ +status_t ENET_SendFrameZeroCopy(ENET_Type *base, + enet_handle_t *handle, + const uint8_t *data, + uint32_t length, + uint8_t ringId, + bool tsFlag, + void *context); + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * @brief The transmit IRQ handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. + * @param ringId The ring id or ring number. + */ +void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId); + +/*! + * @brief The receive IRQ handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. + * @param ringId The ring id or ring number. + */ +void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle, uint32_t ringId); + +/*! + * @brief the common IRQ handler for the tx/rx irq handler. + * + * This is used for the combined tx/rx interrupt for multi-ring (frame 1). + * + * @param base ENET peripheral base address. + */ +void ENET_CommonFrame1IRQHandler(ENET_Type *base); + +/*! + * @brief the common IRQ handler for the tx/rx irq handler. + * + * This is used for the combined tx/rx interrupt for multi-ring (frame 2). + * + * @param base ENET peripheral base address. + */ +void ENET_CommonFrame2IRQHandler(ENET_Type *base); +#else +/*! + * @brief The transmit IRQ handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. + */ +void ENET_TransmitIRQHandler(ENET_Type *base, enet_handle_t *handle); + +/*! + * @brief The receive IRQ handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. + */ +void ENET_ReceiveIRQHandler(ENET_Type *base, enet_handle_t *handle); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +/*! + * @brief Some special IRQ handler including the error, mii, wakeup irq handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. + */ +void ENET_ErrorIRQHandler(ENET_Type *base, enet_handle_t *handle); + +/*! + * @brief the common IRQ handler for the 1588 irq handler. + * + * This is used for the 1588 timer interrupt. + * + * @param base ENET peripheral base address. + */ +void ENET_Ptp1588IRQHandler(ENET_Type *base); + +/*! + * @brief the common IRQ handler for the tx/rx/error etc irq handler. + * + * This is used for the combined tx/rx/error interrupt for single/mutli-ring (frame 0). + * + * @param base ENET peripheral base address. + */ +void ENET_CommonFrame0IRQHandler(ENET_Type *base); +/* @} */ + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * @name ENET PTP 1588 function operation + * @{ + */ +void ENET_Ptp1588ConfigureHandler(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig); + +/*! + * @brief Configures the ENET PTP IEEE 1588 feature with the basic configuration. + * The function sets the clock for PTP 1588 timer and enables + * time stamp interrupts and transmit interrupts for PTP 1588 features. + * This API should be called when the 1588 feature is enabled + * or the ENET_ENHANCEDBUFFERDESCRIPTOR_MODE is defined. + * ENET_Init should be called before calling this API. + * + * @note The PTP 1588 time-stamp second increase though time-stamp interrupt handler + * and the transmit time-stamp store is done through transmit interrupt handler. + * As a result, the TS interrupt and TX interrupt are enabled when you call this API. + * + * @param base ENET peripheral base address. + * @param handle ENET handler pointer. + * @param ptpConfig The ENET PTP1588 configuration. + */ +void ENET_Ptp1588Configure(ENET_Type *base, enet_handle_t *handle, enet_ptp_config_t *ptpConfig); + +/*! + * @brief Starts the ENET PTP 1588 Timer. + * This function is used to initialize the PTP timer. After the PTP starts, + * the PTP timer starts running. + * + * @param base ENET peripheral base address. + * @param ptpClkSrc The clock source of the PTP timer. + */ +void ENET_Ptp1588StartTimer(ENET_Type *base, uint32_t ptpClkSrc); + +/*! + * @brief Stops the ENET PTP 1588 Timer. + * This function is used to stops the ENET PTP timer. + * + * @param base ENET peripheral base address. + */ +static inline void ENET_Ptp1588StopTimer(ENET_Type *base) +{ + /* Disable PTP timer and reset the timer. */ + base->ATCR &= ~ENET_ATCR_EN_MASK; + base->ATCR |= ENET_ATCR_RESTART_MASK; +} + +/*! + * @brief Adjusts the ENET PTP 1588 timer. + * + * @param base ENET peripheral base address. + * @param corrIncrease The correction increment value. This value is added every time the correction + * timer expires. A value less than the PTP timer frequency(1/ptpClkSrc) slows down the timer, + * a value greater than the 1/ptpClkSrc speeds up the timer. + * @param corrPeriod The PTP timer correction counter wrap-around value. This defines after how + * many timer clock the correction counter should be reset and trigger a correction + * increment on the timer. A value of 0 disables the correction counter and no correction occurs. + */ +void ENET_Ptp1588AdjustTimer(ENET_Type *base, uint32_t corrIncrease, uint32_t corrPeriod); + +/*! + * @brief Sets the ENET PTP 1588 timer channel mode. + * + * @param base ENET peripheral base address. + * @param channel The ENET PTP timer channel number. + * @param mode The PTP timer channel mode, see "enet_ptp_timer_channel_mode_t". + * @param intEnable Enables or disables the interrupt. + */ +static inline void ENET_Ptp1588SetChannelMode(ENET_Type *base, + enet_ptp_timer_channel_t channel, + enet_ptp_timer_channel_mode_t mode, + bool intEnable) +{ + uint32_t tcrReg = 0; + + tcrReg = ENET_TCSR_TMODE(mode) | (intEnable ? ENET_TCSR_TIE_MASK : 0U); + + /* Disable channel mode first. */ + base->CHANNEL[channel].TCSR = 0; + base->CHANNEL[channel].TCSR = tcrReg; +} + +#if defined(FSL_FEATURE_ENET_HAS_TIMER_PWCONTROL) && FSL_FEATURE_ENET_HAS_TIMER_PWCONTROL +/*! + * @brief Sets ENET PTP 1588 timer channel mode pulse width. + * + * For the input "mode" in ENET_Ptp1588SetChannelMode, the kENET_PtpChannelPulseLowonCompare + * kENET_PtpChannelPulseHighonCompare only support the pulse width for one 1588 clock. + * this function is extended for control the pulse width from 1 to 32 1588 clock cycles. + * so call this function if you need to set the timer channel mode for + * kENET_PtpChannelPulseLowonCompare or kENET_PtpChannelPulseHighonCompare + * with pulse width more than one 1588 clock, + * + * @param base ENET peripheral base address. + * @param channel The ENET PTP timer channel number. + * @param isOutputLow True --- timer channel is configured for output compare + * pulse output low. + * false --- timer channel is configured for output compare + * pulse output high. + * @param pulseWidth The pulse width control value, range from 0 ~ 31. + * 0 --- pulse width is one 1588 clock cycle. + * 31 --- pulse width is thirty two 1588 clock cycles. + * @param intEnable Enables or disables the interrupt. + */ +static inline void ENET_Ptp1588SetChannelOutputPulseWidth( + ENET_Type *base, enet_ptp_timer_channel_t channel, bool isOutputLow, uint8_t pulseWidth, bool intEnable) +{ + uint32_t tcrReg; + + tcrReg = ENET_TCSR_TIE(intEnable) | ENET_TCSR_TPWC(pulseWidth); + + if (isOutputLow) + { + tcrReg |= ENET_TCSR_TMODE(kENET_PtpChannelPulseLowonCompare); + } + else + { + tcrReg |= ENET_TCSR_TMODE(kENET_PtpChannelPulseHighonCompare); + } + + /* Disable channel mode first. */ + base->CHANNEL[channel].TCSR = 0; + base->CHANNEL[channel].TCSR = tcrReg; +} +#endif /* FSL_FEATURE_ENET_HAS_TIMER_PWCONTROL */ + +/*! + * @brief Sets the ENET PTP 1588 timer channel comparison value. + * + * @param base ENET peripheral base address. + * @param channel The PTP timer channel, see "enet_ptp_timer_channel_t". + * @param cmpValue The compare value for the compare setting. + */ +static inline void ENET_Ptp1588SetChannelCmpValue(ENET_Type *base, enet_ptp_timer_channel_t channel, uint32_t cmpValue) +{ + base->CHANNEL[channel].TCCR = cmpValue; +} + +/*! + * @brief Gets the ENET PTP 1588 timer channel status. + * + * @param base ENET peripheral base address. + * @param channel The IEEE 1588 timer channel number. + * @return True or false, Compare or capture operation status + */ +static inline bool ENET_Ptp1588GetChannelStatus(ENET_Type *base, enet_ptp_timer_channel_t channel) +{ + return (0U != (base->CHANNEL[channel].TCSR & ENET_TCSR_TF_MASK)); +} + +/*! + * @brief Clears the ENET PTP 1588 timer channel status. + * + * @param base ENET peripheral base address. + * @param channel The IEEE 1588 timer channel number. + */ +static inline void ENET_Ptp1588ClearChannelStatus(ENET_Type *base, enet_ptp_timer_channel_t channel) +{ + base->CHANNEL[channel].TCSR |= ENET_TCSR_TF_MASK; + base->TGSR = (1UL << (uint32_t)channel); +} + +/*! + * @brief Get the ENET PTP 1588 timer global status. + * + * @param base ENET peripheral base address. + */ +static inline uint32_t ENET_Ptp1588GetGlobalStatus(ENET_Type *base) +{ + return base->TGSR; +} + +/*! + * @brief Gets the current ENET time from the PTP 1588 timer. + * A variant of ENET_Ptp1588GetTimer() which does not disable interrupts. + * + * @param base ENET peripheral base address. + * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + * @param ptpTime The PTP timer structure. + */ +void ENET_Ptp1588GetTimerNoIrqDisable(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime); + +/*! + * @brief Gets the current ENET time from the PTP 1588 timer. + * + * @param base ENET peripheral base address. + * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + * @param ptpTime The PTP timer structure. + */ +void ENET_Ptp1588GetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime); + +/*! + * @brief Sets the ENET PTP 1588 timer to the assigned time. + * + * @param base ENET peripheral base address. + * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + * @param ptpTime The timer to be set to the PTP timer. + */ +void ENET_Ptp1588SetTimer(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_t *ptpTime); + +/*! + * @brief The IEEE 1588 PTP time stamp interrupt handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET state pointer. This is the same state pointer used in the ENET_Init. + */ +void ENET_TimeStampIRQHandler(ENET_Type *base, enet_handle_t *handle); + +/* @} */ + +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_ENET_H_ */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_enet_qos.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_enet_qos.h new file mode 100644 index 000000000..74b8049a0 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_enet_qos.h @@ -0,0 +1,1768 @@ +/* + * Copyright 2020-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_ENET_QOS_H_ +#define _FSL_ENET_QOS_H_ + +#include "fsl_common.h" +#include "fsl_cache.h" +#if defined(FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET) && FSL_FEATURE_MEMORY_HAS_ADDRESS_OFFSET +#include "fsl_memory.h" +#endif +/*! + * @addtogroup enet_qos_qos + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief Defines the driver version. */ +#define FSL_ENET_QOS_DRIVER_VERSION (MAKE_VERSION(2, 4, 0)) +/*@}*/ + +/*! @name Control and status region bit masks of the receive buffer descriptor. */ +/*@{*/ +/*! @brief Defines for read format. */ +#define ENET_QOS_RXDESCRIP_RD_BUFF1VALID_MASK (1UL << 24U) /*!< Buffer1 address valid. */ +#define ENET_QOS_RXDESCRIP_RD_BUFF2VALID_MASK (1UL << 25U) /*!< Buffer2 address valid. */ +#define ENET_QOS_RXDESCRIP_RD_IOC_MASK (1UL << 30U) /*!< Interrupt enable on complete. */ +#define ENET_QOS_RXDESCRIP_RD_OWN_MASK (1UL << 31U) /*!< Own bit. */ + +/*! @brief Defines for write back format. */ +#define ENET_QOS_RXDESCRIP_WR_ERR_MASK ((1UL << 3U) | (1UL << 7U)) +#define ENET_QOS_RXDESCRIP_WR_PYLOAD_MASK (0x7UL) +#define ENET_QOS_RXDESCRIP_WR_PTPMSGTYPE_MASK (0xF00UL) +#define ENET_QOS_RXDESCRIP_WR_PTPTYPE_MASK (1UL << 12U) +#define ENET_QOS_RXDESCRIP_WR_PTPVERSION_MASK (1UL << 13U) +#define ENET_QOS_RXDESCRIP_WR_PTPTSA_MASK (1UL << 14U) +#define ENET_QOS_RXDESCRIP_WR_PACKETLEN_MASK (0x7FFFUL) +#define ENET_QOS_RXDESCRIP_WR_ERRSUM_MASK (1UL << 15U) +#define ENET_QOS_RXDESCRIP_WR_TYPE_MASK (0x30000UL) +#define ENET_QOS_RXDESCRIP_WR_DE_MASK (1UL << 19U) +#define ENET_QOS_RXDESCRIP_WR_RE_MASK (1UL << 20U) +#define ENET_QOS_RXDESCRIP_WR_OE_MASK (1UL << 21U) +#define ENET_QOS_RXDESCRIP_WR_RWT_MASK (1UL << 22U) +#define ENET_QOS_RXDESCRIP_WR_GP_MASK (1UL << 22U) +#define ENET_QOS_RXDESCRIP_WR_CRC_MASK (1UL << 23U) +#define ENET_QOS_RXDESCRIP_WR_RS0V_MASK (1UL << 25U) +#define ENET_QOS_RXDESCRIP_WR_RS1V_MASK (1UL << 26U) +#define ENET_QOS_RXDESCRIP_WR_RS2V_MASK (1UL << 27U) +#define ENET_QOS_RXDESCRIP_WR_LD_MASK (1UL << 28U) +#define ENET_QOS_RXDESCRIP_WR_FD_MASK (1UL << 29U) +#define ENET_QOS_RXDESCRIP_WR_CTXT_MASK (1UL << 30U) +#define ENET_QOS_RXDESCRIP_WR_OWN_MASK (1UL << 31U) + +#define ENET_QOS_RXDESCRIP_WR_SA_FAILURE_MASK (1UL << 16U) +#define ENET_QOS_RXDESCRIP_WR_DA_FAILURE_MASK (1UL << 17U) +/*@}*/ + +/*! @name Control and status bit masks of the transmit buffer descriptor. */ +/*@{*/ +/*! @brief Defines for read format. */ +#define ENET_QOS_TXDESCRIP_RD_BL1_MASK (0x3fffUL) +#define ENET_QOS_TXDESCRIP_RD_BL2_MASK (ENET_QOS_TXDESCRIP_RD_BL1_MASK << 16U) +#define ENET_QOS_TXDESCRIP_RD_BL1(n) ((uint32_t)(n)&ENET_QOS_TXDESCRIP_RD_BL1_MASK) +#define ENET_QOS_TXDESCRIP_RD_BL2(n) (((uint32_t)(n)&ENET_QOS_TXDESCRIP_RD_BL1_MASK) << 16) +#define ENET_QOS_TXDESCRIP_RD_TTSE_MASK (1UL << 30UL) +#define ENET_QOS_TXDESCRIP_RD_IOC_MASK (1UL << 31UL) + +#define ENET_QOS_TXDESCRIP_RD_FL_MASK (0x7FFFUL) +#define ENET_QOS_TXDESCRIP_RD_FL(n) ((uint32_t)(n)&ENET_QOS_TXDESCRIP_RD_FL_MASK) +#define ENET_QOS_TXDESCRIP_RD_CIC(n) (((uint32_t)(n)&0x3U) << 16U) +#define ENET_QOS_TXDESCRIP_RD_TSE_MASK (1UL << 18U) +#define ENET_QOS_TXDESCRIP_RD_SLOT(n) (((uint32_t)(n)&0x0fU) << 19U) +#define ENET_QOS_TXDESCRIP_RD_SAIC(n) (((uint32_t)(n)&0x07U) << 23U) +#define ENET_QOS_TXDESCRIP_RD_CPC(n) (((uint32_t)(n)&0x03U) << 26U) +#define ENET_QOS_TXDESCRIP_RD_LDFD(n) (((uint32_t)(n)&0x03U) << 28U) +#define ENET_QOS_TXDESCRIP_RD_LD_MASK (1UL << 28U) +#define ENET_QOS_TXDESCRIP_RD_FD_MASK (1UL << 29U) +#define ENET_QOS_TXDESCRIP_RD_CTXT_MASK (1UL << 30U) +#define ENET_QOS_TXDESCRIP_RD_OWN_MASK (1UL << 31U) + +/*! @brief Defines for write back format. */ +#define ENET_QOS_TXDESCRIP_WB_TTSS_MASK (1UL << 17U) +/*@}*/ + +/*! @name Bit mask for interrupt enable type. */ +/*@{*/ +#define ENET_QOS_ABNORM_INT_MASK \ + (ENET_QOS_DMA_CHX_INT_EN_TXSE_MASK | ENET_QOS_DMA_CHX_INT_EN_RBUE_MASK | ENET_QOS_DMA_CHX_INT_EN_RSE_MASK | \ + ENET_QOS_DMA_CHX_INT_EN_RWTE_MASK | ENET_QOS_DMA_CHX_INT_EN_FBEE_MASK | ENET_QOS_DMA_CHX_INT_EN_ETIE_MASK) +#define ENET_QOS_NORM_INT_MASK \ + (ENET_QOS_DMA_CHX_INT_EN_TIE_MASK | ENET_QOS_DMA_CHX_INT_EN_TBUE_MASK | ENET_QOS_DMA_CHX_INT_EN_RIE_MASK | \ + ENET_QOS_DMA_CHX_INT_EN_ERIE_MASK) +/*@}*/ + +/*! @name Defines some Ethernet parameters. */ +/*@{*/ +#ifndef ENET_QOS_RING_NUM_MAX +#define ENET_QOS_RING_NUM_MAX (5U) /*!< The Maximum number of tx/rx descriptor rings. */ +#endif +#define ENET_QOS_FRAME_MAX_FRAMELEN (1518U) /*!< Default maximum Ethernet frame size. */ +#define ENET_QOS_FCS_LEN (4U) /*!< Ethernet FCS length. */ +#define ENET_QOS_ADDR_ALIGNMENT (0x3U) /*!< Recommended Ethernet buffer alignment. */ +#define ENET_QOS_BUFF_ALIGNMENT (8U) /*!< Receive buffer alignment shall be 4bytes-aligned. */ +#define ENET_QOS_MTL_RXFIFOSIZE (8192U) /*!< The rx fifo size. */ +#define ENET_QOS_MTL_TXFIFOSIZE (8192U) /*!< The tx fifo size. */ +#define ENET_QOS_MACINT_ENUM_OFFSET (16U) /*!< The offest for mac interrupt in enum type. */ +#define ENET_QOS_RXP_ENTRY_COUNT (256U) /*!< RXP table entry count, implied by FRPES in MAC_HW_FEATURE3 */ +#define ENET_QOS_RXP_BUFFER_SIZE (256U) /*!< RXP Buffer size, implied by FRPBS in MAC_HW_FEATURE3 */ +#define ENET_QOS_EST_WID (24U) /*!< Width of the time interval in Gate Control List */ +#define ENET_QOS_EST_DEP (512U) /*!< Maxmimum depth of Gate Control List */ +/*@}*/ + +/*! @brief Defines the status return codes for transaction. */ +enum +{ + kStatus_ENET_QOS_InitMemoryFail = + MAKE_STATUS(kStatusGroup_ENET_QOS, 0U), /*!< Init fails since buffer memory is not enough. */ + kStatus_ENET_QOS_RxFrameError = + MAKE_STATUS(kStatusGroup_ENET_QOS, 1U), /*!< A frame received but data error happen. */ + kStatus_ENET_QOS_RxFrameFail = MAKE_STATUS(kStatusGroup_ENET_QOS, 2U), /*!< Failed to receive a frame. */ + kStatus_ENET_QOS_RxFrameEmpty = MAKE_STATUS(kStatusGroup_ENET_QOS, 3U), /*!< No frame arrive. */ + kStatus_ENET_QOS_RxFrameDrop = + MAKE_STATUS(kStatusGroup_ENET_QOS, 4U), /*!< Rx frame is dropped since no buffer memory. */ + kStatus_ENET_QOS_TxFrameBusy = + MAKE_STATUS(kStatusGroup_ENET_QOS, 5U), /*!< Transmit descriptors are under process. */ + kStatus_ENET_QOS_TxFrameFail = MAKE_STATUS(kStatusGroup_ENET_QOS, 6U), /*!< Transmit frame fail. */ + kStatus_ENET_QOS_TxFrameOverLen = MAKE_STATUS(kStatusGroup_ENET_QOS, 7U), /*!< Transmit oversize. */ + kStatus_ENET_QOS_Est_SwListBusy = + MAKE_STATUS(kStatusGroup_ENET_QOS, 8U), /*!< SW Gcl List not yet processed by HW. */ + kStatus_ENET_QOS_Est_SwListWriteAbort = MAKE_STATUS(kStatusGroup_ENET_QOS, 9U), /*!< SW Gcl List write aborted .*/ + kStatus_ENET_QOS_Est_InvalidParameter = + MAKE_STATUS(kStatusGroup_ENET_QOS, 10U), /*!< Invalid parameter in Gcl List .*/ + kStatus_ENET_QOS_Est_BtrError = MAKE_STATUS(kStatusGroup_ENET_QOS, 11U), /*!< Base Time Error when loading list.*/ + kStatus_ENET_QOS_TrgtBusy = MAKE_STATUS(kStatusGroup_ENET_QOS, 12U), /*!< Target time register busy.*/ + kStatus_ENET_QOS_Timeout = MAKE_STATUS(kStatusGroup_ENET_QOS, 13U), /*!< Target time register busy.*/ + kStatus_ENET_QOS_PpsBusy = MAKE_STATUS(kStatusGroup_ENET_QOS, 14U) /*!< Pps command busy.*/ +}; + +/*! @brief Defines the MII/RGMII mode for data interface between the MAC and the PHY. */ +typedef enum _enet_qos_mii_mode +{ + kENET_QOS_MiiMode = 0U, /*!< MII mode for data interface. */ + kENET_QOS_RgmiiMode = 1U, /*!< RGMII mode for data interface. */ + kENET_QOS_RmiiMode = 4U /*!< RMII mode for data interface. */ +} enet_qos_mii_mode_t; + +/*! @brief Defines the 10/100/1000 Mbps speed for the MII data interface. */ +typedef enum _enet_qos_mii_speed +{ + kENET_QOS_MiiSpeed10M = + ENET_QOS_MAC_CONFIGURATION_PS(1U) | ENET_QOS_MAC_CONFIGURATION_FES(0U), /*!< Speed 10 Mbps. */ + kENET_QOS_MiiSpeed100M = + ENET_QOS_MAC_CONFIGURATION_PS(1U) | ENET_QOS_MAC_CONFIGURATION_FES(1U), /*!< Speed 100 Mbps. */ + kENET_QOS_MiiSpeed1000M = + ENET_QOS_MAC_CONFIGURATION_PS(0U) | ENET_QOS_MAC_CONFIGURATION_FES(0U), /*!< Speed 1000 Mbps. */ + kENET_QOS_MiiSpeed2500M = + ENET_QOS_MAC_CONFIGURATION_PS(0U) | ENET_QOS_MAC_CONFIGURATION_FES(1U) /*!< Speed 2500 Mbps. */ +} enet_qos_mii_speed_t; + +/*! @brief Defines the half or full duplex for the MII data interface. */ +typedef enum _enet_qos_mii_duplex +{ + kENET_QOS_MiiHalfDuplex = 0U, /*!< Half duplex mode. */ + kENET_QOS_MiiFullDuplex /*!< Full duplex mode. */ +} enet_qos_mii_duplex_t; + +/*! @brief Define the MII opcode for normal MDIO_CLAUSES_22 Frame. */ +typedef enum _enet_qos_mii_normal_opcode +{ + kENET_QOS_MiiWriteFrame = + ENET_QOS_MAC_MDIO_ADDRESS_GOC_1(0U) | + ENET_QOS_MAC_MDIO_ADDRESS_GOC_0(1U), /*!< Write frame operation for a valid MII management frame. */ + kENET_QOS_MiiReadFrame = + ENET_QOS_MAC_MDIO_ADDRESS_GOC_1(1U) | + ENET_QOS_MAC_MDIO_ADDRESS_GOC_0(1U) /*!< Read frame operation for a valid MII management frame. */ +} enet_qos_mii_normal_opcode; + +/*! @brief Define the DMA maximum transmit burst length. */ +typedef enum _enet_qos_dma_burstlen +{ + kENET_QOS_BurstLen1 = 0x00001U, /*!< DMA burst length 1. */ + kENET_QOS_BurstLen2 = 0x00002U, /*!< DMA burst length 2. */ + kENET_QOS_BurstLen4 = 0x00004U, /*!< DMA burst length 4. */ + kENET_QOS_BurstLen8 = 0x00008U, /*!< DMA burst length 8. */ + kENET_QOS_BurstLen16 = 0x00010U, /*!< DMA burst length 16. */ + kENET_QOS_BurstLen32 = 0x00020U, /*!< DMA burst length 32. */ + kENET_QOS_BurstLen64 = 0x10008U, /*!< DMA burst length 64. eight times enabled. */ + kENET_QOS_BurstLen128 = 0x10010U, /*!< DMA burst length 128. eight times enabled. */ + kENET_QOS_BurstLen256 = 0x10020U, /*!< DMA burst length 256. eight times enabled. */ +} enet_qos_dma_burstlen; + +/*! @brief Define the flag for the descriptor. */ +typedef enum _enet_qos_desc_flag +{ + kENET_QOS_MiddleFlag = 0, /*!< It's a middle descriptor of the frame. */ + kENET_QOS_LastFlagOnly, /*!< It's the last descriptor of the frame. */ + kENET_QOS_FirstFlagOnly, /*!< It's the first descriptor of the frame. */ + kENET_QOS_FirstLastFlag /*!< It's the first and last descriptor of the frame. */ +} enet_qos_desc_flag; + +/*! @brief Define the system time adjust operation control. */ +typedef enum _enet_qos_systime_op +{ + kENET_QOS_SystimeAdd = 0U, /*!< System time add to. */ + kENET_QOS_SystimeSubtract = 1U /*!< System time subtract. */ +} enet_qos_systime_op; + +/*! @brief Define the system time rollover control. */ +typedef enum _enet_qos_ts_rollover_type +{ + kENET_QOS_BinaryRollover = 0, /*!< System time binary rollover.*/ + kENET_QOS_DigitalRollover = 1 /*!< System time digital rollover.*/ +} enet_qos_ts_rollover_type; + +/*! @brief Defines some special configuration for ENET. + * + * These control flags are provided for special user requirements. + * Normally, these is no need to set this control flags for ENET initialization. + * But if you have some special requirements, set the flags to specialControl + * in the enet_qos_config_t. + * @note "kENET_QOS_StoreAndForward" is recommended to be set. + */ +typedef enum _enet_qos_special_config +{ + + /***********************DMA CONFGI**********************************************/ + kENET_QOS_DescDoubleBuffer = 0x0001U, /*!< The double buffer is used in the tx/rx descriptor. */ + /**************************MTL************************************/ + kENET_QOS_StoreAndForward = 0x0002U, /*!< The rx/tx store and forward enable. */ + /***********************MAC****************************************/ + kENET_QOS_PromiscuousEnable = 0x0004U, /*!< The promiscuous enabled. */ + kENET_QOS_FlowControlEnable = 0x0008U, /*!< The flow control enabled. */ + kENET_QOS_BroadCastRxDisable = 0x0010U, /*!< The broadcast disabled. */ + kENET_QOS_MulticastAllEnable = 0x0020U, /*!< All multicast are passed. */ + kENET_QOS_8023AS2KPacket = 0x0040U, /*!< 8023as support for 2K packets. */ + kENET_QOS_HashMulticastEnable = 0x0080U /*!< The multicast packets are filtered through hash table. */ +} enet_qos_special_config_t; + +/*! @brief List of DMA interrupts supported by the ENET interrupt. This + * enumeration uses one-bot encoding to allow a logical OR of multiple + * members. + */ +typedef enum _enet_qos_dma_interrupt_enable +{ + kENET_QOS_DmaTx = ENET_QOS_DMA_CHX_INT_EN_TIE_MASK, /*!< Tx interrupt. */ + kENET_QOS_DmaTxStop = ENET_QOS_DMA_CHX_INT_EN_TXSE_MASK, /*!< Tx stop interrupt. */ + kENET_QOS_DmaTxBuffUnavail = ENET_QOS_DMA_CHX_INT_EN_TBUE_MASK, /*!< Tx buffer unavailable. */ + kENET_QOS_DmaRx = ENET_QOS_DMA_CHX_INT_EN_RIE_MASK, /*!< Rx interrupt. */ + kENET_QOS_DmaRxBuffUnavail = ENET_QOS_DMA_CHX_INT_EN_RBUE_MASK, /*!< Rx buffer unavailable. */ + kENET_QOS_DmaRxStop = ENET_QOS_DMA_CHX_INT_EN_RSE_MASK, /*!< Rx stop. */ + kENET_QOS_DmaRxWatchdogTimeout = ENET_QOS_DMA_CHX_INT_EN_RWTE_MASK, /*!< Rx watchdog timeout. */ + kENET_QOS_DmaEarlyTx = ENET_QOS_DMA_CHX_INT_EN_ETIE_MASK, /*!< Early transmit. */ + kENET_QOS_DmaEarlyRx = ENET_QOS_DMA_CHX_INT_EN_ERIE_MASK, /*!< Early receive. */ + kENET_QOS_DmaBusErr = ENET_QOS_DMA_CHX_INT_EN_FBEE_MASK, /*!< Fatal bus error. */ +} enet_qos_dma_interrupt_enable_t; + +/*! @brief List of mac interrupts supported by the ENET interrupt. This + * enumeration uses one-bot encoding to allow a logical OR of multiple + * members. + */ +typedef enum _enet_qos_mac_interrupt_enable +{ + kENET_QOS_MacPmt = (ENET_QOS_MAC_INTERRUPT_ENABLE_PMTIE_MASK << ENET_QOS_MACINT_ENUM_OFFSET), + kENET_QOS_MacTimestamp = (ENET_QOS_MAC_INTERRUPT_ENABLE_TSIE_MASK << ENET_QOS_MACINT_ENUM_OFFSET), +} enet_qos_mac_interrupt_enable_t; + +/*! @brief Defines the common interrupt event for callback use. */ +typedef enum _enet_qos_event +{ + kENET_QOS_RxIntEvent, /*!< Receive interrupt event. */ + kENET_QOS_TxIntEvent, /*!< Transmit interrupt event. */ + kENET_QOS_WakeUpIntEvent, /*!< Wake up interrupt event. */ + kENET_QOS_TimeStampIntEvent, /*!< Time stamp interrupt event. */ +} enet_qos_event_t; + +/*! @brief Define the MTL mode for multiple queues/rings. */ +typedef enum _enet_qos_queue_mode +{ + kENET_QOS_AVB_Mode = 1U, /*!< Enable queue in AVB mode. */ + kENET_QOS_DCB_Mode = 2U, /*!< Enable queue in DCB mode. */ +} enet_qos_queue_mode_t; + +/*! @brief Define the MTL tx scheduling algorithm for multiple queues/rings. */ +typedef enum _enet_qos_mtl_multiqueue_txsche +{ + kENET_QOS_txWeightRR = 0U, /*!< Tx weight round-robin. */ + kENET_QOS_txWeightFQ = 1U, /*!< Tx weight fair queuing. */ + kENET_QOS_txDefictWeightRR = 2U, /*!< Tx deficit weighted round-robin. */ + kENET_QOS_txStrPrio = 3U, /*!< Tx strict priority. */ +} enet_qos_mtl_multiqueue_txsche; + +/*! @brief Define the MTL rx scheduling algorithm for multiple queues/rings. */ +typedef enum _enet_qos_mtl_multiqueue_rxsche +{ + kENET_QOS_rxStrPrio = 0U, /*!< Rx strict priority, Queue 0 has the lowest priority. */ + kENET_QOS_rxWeightStrPrio, /*!< Weighted Strict Priority. */ +} enet_qos_mtl_multiqueue_rxsche; + +/*! @brief Define the MTL rx queue and DMA channel mapping. */ +typedef enum _enet_qos_mtl_rxqueuemap +{ + kENET_QOS_StaticDirctMap = 0x100U, /*!< The received fame in rx Qn(n = 0,1) directly map to dma channel n. */ + kENET_QOS_DynamicMap = + 0x1010U, /*!< The received frame in rx Qn(n = 0,1) map to the dma channel m(m = 0,1) related with the same Mac. + */ +} enet_qos_mtl_rxqueuemap_t; + +/*! @brief Defines the package type for receive queue routing. */ +typedef enum _enet_qos_rx_queue_route +{ + kENET_QOS_PacketNoQ = 0x0, /* Not specific queue */ + kENET_QOS_PacketAVCPQ = (1U << 0U), /* AV Untagged Control Packets Queue */ + kENET_QOS_PacketPTPQ = (1U << 1U), /* PTP Packets Queue */ + kENET_QOS_PacketDCBCPQ = (1U << 2U), /* DCB Control Packets Queue */ + kENET_QOS_PacketUPQ = (1U << 3U), /* Untagged Packets Queue */ + kENET_QOS_PacketMCBCQ = (1U << 4U), /* Multicast & Broadcast Packets Queue */ +} enet_qos_rx_queue_route_t; + +/*! @brief Defines the ENET PTP message related constant. */ +typedef enum _enet_qos_ptp_event_type +{ + kENET_QOS_PtpEventMsgType = 3U, /*!< PTP event message type. */ + kENET_QOS_PtpSrcPortIdLen = 10U, /*!< PTP message sequence id length. */ + kENET_QOS_PtpEventPort = 319U, /*!< PTP event port number. */ + kENET_QOS_PtpGnrlPort = 320U /*!< PTP general port number. */ +} enet_qos_ptp_event_type_t; + +/*! @brief Defines the PPS instance numbers. */ +typedef enum _enet_qos_ptp_pps_instance +{ + kENET_QOS_PtpPpsIstance0 = 0U, /*!< PPS instance 0. */ + kENET_QOS_PtpPpsIstance1, /*!< PPS instance 1. */ + kENET_QOS_PtpPpsIstance2, /*!< PPS instance 2. */ + kENET_QOS_PtpPpsIstance3 /*!< PPS instance 3. */ +} enet_qos_ptp_pps_instance_t; + +/*! @brief Defines the Target Time register mode. */ +typedef enum _enet_qos_ptp_pps_trgt_mode +{ + kENET_QOS_PtpPpsTrgtModeOnlyInt = 0U, /*!< Only interrupts. */ + kENET_QOS_PtpPpsTrgtModeIntSt = 2, /*!< Both interrupt and output signal. */ + kENET_QOS_PtpPpsTrgtModeOnlySt = 3, /*!< Only output signal. */ +} enet_qos_ptp_pps_trgt_mode_t; + +/*! @brief Defines commands for ppscmd register. */ +typedef enum _enet_qos_ptp_pps_cmd +{ + kENET_QOS_PtpPpsCmdNC = 0U, /*!< No Command. */ + kENET_QOS_PtpPpsCmdSSP = 1U, /*!< Start Single Pulse. */ + kENET_QOS_PtpPpsCmdSPT = 2U, /*!< Start Pulse Train. */ + kENET_QOS_PtpPpsCmdCS = 3U, /*!< Cancel Start. */ + kENET_QOS_PtpPpsCmdSPTAT = 4U, /*!< Stop Pulse Train At Time. */ + kENET_QOS_PtpPpsCmdSPTI = 5U, /*!< Stop Pulse Train Immediately. */ + kENET_QOS_PtpPpsCmdCSPT = 6U, /*!< Cancel Stop Pulse Train. */ +} enet_qos_ptp_pps_cmd_t; + +/*! @brief Defines the enmueration of ETS list length. + */ +typedef enum _enet_qos_ets_list_length +{ + kENET_QOS_Ets_List_64 = 7U, /*!< List length of 64 */ + kENET_QOS_Ets_List_128 = 8U, /*!< List length of 128 */ + kENET_QOS_Ets_List_256 = 9U, /*!< List length of 256 */ + kENET_QOS_Ets_List_512 = 10U, /*!< List length of 512 */ + kENET_QOS_Ets_List_1024 = 11U, /*!< List length of 1024 */ +} enet_qos_ets_list_length_t; + +/*! @brief Defines the enmueration of ETS gate control address. + */ +typedef enum _enet_qos_ets_gccr_addr +{ + kENET_QOS_Ets_btr_low = 0U, /*!< BTR Low */ + kENET_QOS_Ets_btr_high = 1U, /*!< BTR High */ + kENET_QOS_Ets_ctr_low = 2U, /*!< CTR Low */ + kENET_QOS_Ets_ctr_high = 3U, /*!< CTR High */ + kENET_QOS_Ets_ter = 4U, /*!< TER */ + kENET_QOS_Ets_llr = 5U, /*!< LLR */ +} enet_qos_ets_gccr_addr_t; + +/*! @brief Defines the enmueration of DMA channel used + * for rx parser entry. + */ +typedef enum _enet_qos_rxp_dma_chn +{ + kENET_QOS_Rxp_DMAChn0 = 1U, /*!< DMA Channel 0 used for RXP entry match */ + kENET_QOS_Rxp_DMAChn1 = 2U, /*!< DMA Channel 1 used for RXP entry match */ + kENET_QOS_Rxp_DMAChn2 = 4U, /*!< DMA Channel 2 used for RXP entry match */ + kENET_QOS_Rxp_DMAChn3 = 8U, /*!< DMA Channel 3 used for RXP entry match */ + kENET_QOS_Rxp_DMAChn4 = 16U, /*!< DMA Channel 4 used for RXP entry match */ +} enet_qos_rxp_dma_chn_t; + +/*! @brief Defines the receive descriptor structure + * has the read-format and write-back format structure. They both + * has the same size with different region definition. so + * we define the read-format region as the receive descriptor structure + * Use the read-format region mask bits in the descriptor initialization + * Use the write-back format region mask bits in the receive data process. + */ +typedef struct _enet_qos_rx_bd_struct +{ + __IO uint32_t buff1Addr; /*!< Buffer 1 address */ + __IO uint32_t reserved; /*!< Reserved */ + __IO uint32_t buff2Addr; /*!< Buffer 2 or next descriptor address */ + __IO uint32_t control; /*!< Buffer 1/2 byte counts and control */ +} enet_qos_rx_bd_struct_t; + +/*! @brief Defines the transmit descriptor structure + * has the read-format and write-back format structure. They both + * has the same size with different region definition. so + * we define the read-format region as the transmit descriptor structure + * Use the read-format region mask bits in the descriptor initialization + * Use the write-back format region mask bits in the transmit data process. + */ +typedef struct _enet_qos_tx_bd_struct +{ + __IO uint32_t buff1Addr; /*!< Buffer 1 address */ + __IO uint32_t buff2Addr; /*!< Buffer 2 address */ + __IO uint32_t buffLen; /*!< Buffer 1/2 byte counts */ + __IO uint32_t controlStat; /*!< TDES control and status word */ +} enet_qos_tx_bd_struct_t; + +/*! @brief Defines the ENET PTP time stamp structure. */ +typedef struct _enet_qos_ptp_time +{ + uint64_t second; /*!< Second. */ + uint32_t nanosecond; /*!< Nanosecond. */ +} enet_qos_ptp_time_t; + +/*! @brief Defines the frame info structure. */ +typedef struct enet_qos_frame_info +{ + void *context; /*!< User specified data, could be buffer address for free */ + bool isTsAvail; /*!< Flag indicates timestamp available status */ + enet_qos_ptp_time_t timeStamp; /*!< Timestamp of frame */ +} enet_qos_frame_info_t; + +/*! @brief Defines the ENET transmit dirty addresses ring/queue structure. */ +typedef struct _enet_qos_tx_dirty_ring +{ + enet_qos_frame_info_t *txDirtyBase; /*!< Dirty buffer descriptor base address pointer. */ + uint16_t txGenIdx; /*!< tx generate index. */ + uint16_t txConsumIdx; /*!< tx consume index. */ + uint16_t txRingLen; /*!< tx ring length. */ + bool isFull; /*!< tx ring is full flag, add this parameter to avoid waste one element. */ +} enet_qos_tx_dirty_ring_t; + +/*! @brief Defines the ENET PTP configuration structure. */ +typedef struct _enet_qos_ptp_config +{ + bool fineUpdateEnable; /*!< Use the fine update. */ + uint32_t defaultAddend; /*!< Default addend value when fine update is enable, could be 2^32 / (refClk_Hz / + ENET_QOS_MICRSECS_ONESECOND / ENET_QOS_SYSTIME_REQUIRED_CLK_MHZ). */ + uint32_t systemTimeClock_Hz; /*! The desired system time frequency. Must be lower than reference clock. (Only used + with fine correction method). */ + bool ptp1588V2Enable; /*!< ptp 1588 version 2 is used. */ + enet_qos_ts_rollover_type tsRollover; /*!< 1588 time nanosecond rollover. */ +} enet_qos_ptp_config_t; + +/*! @brief Defines the EST gate operation structure. */ +typedef struct _enet_qos_est_gate_op +{ + uint32_t gate; + uint32_t interval; +} enet_qos_est_gate_op_t; + +/*! @brief Defines the EST gate control list structure. */ +typedef struct _enet_qos_est_gcl +{ + bool enable; /*!< Enable or disable EST */ + uint64_t baseTime; /*! Base Time 32 bits seconds 32 bits nanoseconds */ + uint64_t cycleTime; /*! Cycle Time 32 bits seconds 32 bits nanoseconds */ + uint32_t extTime; /*! Time Extension 32 bits seconds 32 bits nanoseconds */ + uint32_t numEntries; /*! Number of entries */ + enet_qos_est_gate_op_t *opList; /*! Pointer to GCL list size */ +} enet_qos_est_gcl_t; + +/*! @brief Defines the ENET_QOS Rx parser configuration structure.*/ +typedef struct _enet_qos_rxp_config +{ + uint32_t matchData; /*! 4-byte match data used for comparing with incoming packet */ + uint32_t matchEnable; /*! When matchEnable is set to 1, the matchData is used for comparing */ + uint8_t acceptFrame : 1; /*! When acceptFrame = 1 and data is matched, the frame will be sent to DMA channel */ + uint8_t rejectFrame : 1; /*! When rejectFrame = 1 and data is matched, the frame will be dropped */ + uint8_t inverseMatch : 1; /*! Inverse match */ + uint8_t nextControl : 1; /*! Next instruction indexing control */ + uint8_t reserved : 4; /*! Reserved control fields */ + uint8_t frameOffset; /*! Frame offset in the packet data to be compared for match, in terms of 4 bytes. */ + uint8_t okIndex; /*! Memory Index to be used next. */ + uint8_t dmaChannel; /*! The DMA channel enet_qos_rxp_dma_chn_t used for receiving the frame when frame match and + acceptFrame = 1 */ + uint32_t reserved2; /*! Reserved for future enhancements */ +} enet_qos_rxp_config_t; + +/*! @brief Defines the buffer descriptor configure structure. + * + * @note + * 1. The receive and transmit descriptor start address pointer and tail pointer must be word-aligned. + * 2. The recommended minimum tx/rx ring length is 4. + * 3. The tx/rx descriptor tail address shall be the address pointer to the address just after the end + * of the last last descriptor. because only the descriptors between the start address and the + * tail address will be used by DMA. + * 4. The descriptor address is the start address of all used contiguous memory. + * for example, the rxDescStartAddrAlign is the start address of rxRingLen contiguous descriptor memories + * for rx descriptor ring 0. + * 5. The "*rxBufferstartAddr" is the first element of rxRingLen (2*rxRingLen for double buffers) + * rx buffers. It means the *rxBufferStartAddr is the rx buffer for the first descriptor + * the *rxBufferStartAddr + 1 is the rx buffer for the second descriptor or the rx buffer for + * the second buffer in the first descriptor. so please make sure the rxBufferStartAddr is the + * address of a rxRingLen or 2*rxRingLen array. + */ +typedef struct _enet_qos_buffer_config +{ + uint8_t rxRingLen; /*!< The length of receive buffer descriptor ring. */ + uint8_t txRingLen; /*!< The length of transmit buffer descriptor ring. */ + enet_qos_tx_bd_struct_t *txDescStartAddrAlign; /*!< Aligned transmit descriptor start address. */ + enet_qos_tx_bd_struct_t *txDescTailAddrAlign; /*!< Aligned transmit descriptor tail address. */ + enet_qos_frame_info_t *txDirtyStartAddr; /*!< Start address of the dirty tx frame information. */ + enet_qos_rx_bd_struct_t *rxDescStartAddrAlign; /*!< Aligned receive descriptor start address. */ + enet_qos_rx_bd_struct_t *rxDescTailAddrAlign; /*!< Aligned receive descriptor tail address. */ + uint32_t *rxBufferStartAddr; /*!< Start address of the rx buffers. */ + uint32_t rxBuffSizeAlign; /*!< Aligned receive data buffer size. */ + bool rxBuffNeedMaintain; /*!< Whether receive data buffer need cache maintain. */ +} enet_qos_buffer_config_t; + +/*! @brief Defines the CBS configuration for queue. */ +typedef struct _enet_qos_cbs_config +{ + uint16_t sendSlope; /*!< Send slope configuration. */ + uint16_t idleSlope; /*!< Idle slope configuration. */ + uint32_t highCredit; /*!< High credit. */ + uint32_t lowCredit; /*!< Low credit. */ +} enet_qos_cbs_config_t; + +/*! @brief Defines the queue configuration structure. */ +typedef struct enet_qos_tx_queue_config +{ + enet_qos_queue_mode_t mode; /*!< tx queue mode configuration. */ + uint32_t weight; /*!< Refer to the MTL TxQ Quantum Weight register. */ + uint32_t priority; /*!< Refer to Transmit Queue Priority Mapping register. */ + enet_qos_cbs_config_t *cbsConfig; /*!< CBS configuration if queue use AVB mode. */ +} enet_qos_queue_tx_config_t; + +/*! @brief Defines the queue configuration structure. */ +typedef struct enet_qos_rx_queue_config +{ + enet_qos_queue_mode_t mode; /*!< rx queue mode configuration. */ + uint8_t mapChannel; /*!< tx queue map dma channel. */ + uint32_t priority; /*!< Rx queue priority. */ + enet_qos_rx_queue_route_t packetRoute; /*!< Receive packet routing. */ +} enet_qos_queue_rx_config_t; + +/*! @brief Defines the configuration when multi-queue is used. */ +typedef struct enet_qos_multiqueue_config +{ + enet_qos_dma_burstlen burstLen; /*!< Burst len for the multi-queue. */ + uint8_t txQueueUse; /*!< Used Tx queue count. */ + enet_qos_mtl_multiqueue_txsche mtltxSche; /*!< Transmit schedule for multi-queue. */ + enet_qos_queue_tx_config_t txQueueConfig[ENET_QOS_RING_NUM_MAX]; /*!< Tx Queue configuration. */ + uint8_t rxQueueUse; /*!< Used Rx queue count. */ + enet_qos_mtl_multiqueue_rxsche mtlrxSche; /*!< Receive schedule for multi-queue. */ + enet_qos_queue_rx_config_t rxQueueConfig[ENET_QOS_RING_NUM_MAX]; /*!< Rx Queue configuration. */ +} enet_qos_multiqueue_config_t; + +/*! @brief Defines the Rx memory buffer alloc function pointer. */ +typedef void *(*enet_qos_rx_alloc_callback_t)(ENET_QOS_Type *base, void *userData, uint8_t channel); + +/*! @brief Defines the Rx memory buffer free function pointer. */ +typedef void (*enet_qos_rx_free_callback_t)(ENET_QOS_Type *base, void *buffer, void *userData, uint8_t channel); + +/*! @brief Defines the basic configuration structure for the ENET device. + * + * @note Default the signal queue is used so the "*multiqueueCfg" is set default + * with NULL. Set the pointer with a valid configuration pointer if the multiple + * queues are required. If multiple queue is enabled, please make sure the + * buffer configuration for all are prepared also. + */ +typedef struct _enet_qos_config +{ + uint16_t specialControl; /*!< The logic or of enet_qos_special_config_t */ + enet_qos_multiqueue_config_t *multiqueueCfg; /*!< Use multi-queue. */ + /* -----------------MAC block-------------------------------*/ + enet_qos_mii_mode_t miiMode; /*!< MII mode. */ + enet_qos_mii_speed_t miiSpeed; /*!< MII Speed. */ + enet_qos_mii_duplex_t miiDuplex; /*!< MII duplex. */ + uint16_t + pauseDuration; /*!< Used in the tx flow control frame, only valid when kENET_QOS_FlowControlEnable is set. */ + /* -----------------Timestamp -------------------------------*/ + enet_qos_ptp_config_t *ptpConfig; /*!< PTP 1588 feature configuration */ + uint32_t csrClock_Hz; /*!< CSR clock frequency in HZ. */ + enet_qos_rx_alloc_callback_t rxBuffAlloc; /*!< Callback to alloc memory, must be provided for zero-copy Rx. */ + enet_qos_rx_free_callback_t rxBuffFree; /*!< Callback to free memory, must be provided for zero-copy Rx. */ +} enet_qos_config_t; + +/* Forward declaration of the handle typedef. */ +typedef struct _enet_qos_handle enet_qos_handle_t; + +/*! @brief ENET callback function. */ +typedef void (*enet_qos_callback_t)( + ENET_QOS_Type *base, enet_qos_handle_t *handle, enet_qos_event_t event, uint8_t channel, void *userData); + +/*! @brief Defines the ENET transmit buffer descriptor ring/queue structure. */ +typedef struct _enet_qos_tx_bd_ring +{ + enet_qos_tx_bd_struct_t *txBdBase; /*!< Buffer descriptor base address pointer. */ + uint16_t txGenIdx; /*!< tx generate index. */ + uint16_t txConsumIdx; /*!< tx consume index. */ + volatile uint16_t txDescUsed; /*!< tx descriptor used number. */ + uint16_t txRingLen; /*!< tx ring length. */ +} enet_qos_tx_bd_ring_t; + +/*! @brief Defines the ENET receive buffer descriptor ring/queue structure. */ +typedef struct _enet_qos_rx_bd_ring +{ + enet_qos_rx_bd_struct_t *rxBdBase; /*!< Buffer descriptor base address pointer. */ + uint16_t rxGenIdx; /*!< The current available receive buffer descriptor pointer. */ + uint16_t rxRingLen; /*!< Receive ring length. */ + uint32_t rxBuffSizeAlign; /*!< Receive buffer size. */ +} enet_qos_rx_bd_ring_t; + +/*! @brief Defines the ENET handler structure. */ +struct _enet_qos_handle +{ + uint8_t txQueueUse; /*!< Used tx queue count. */ + uint8_t rxQueueUse; /*!< Used rx queue count. */ + bool doubleBuffEnable; /*!< The double buffer is used in the descriptor. */ + bool rxintEnable; /*!< Rx interrupt enabled. */ + bool rxMaintainEnable[ENET_QOS_RING_NUM_MAX]; /*!< Rx buffer cache maintain enabled. */ + enet_qos_rx_bd_ring_t rxBdRing[ENET_QOS_RING_NUM_MAX]; /*!< Receive buffer descriptor. */ + enet_qos_tx_bd_ring_t txBdRing[ENET_QOS_RING_NUM_MAX]; /*!< Transmit buffer descriptor. */ + enet_qos_tx_dirty_ring_t txDirtyRing[ENET_QOS_RING_NUM_MAX]; /*!< Transmit dirty buffers addresses. */ + uint32_t *rxBufferStartAddr[ENET_QOS_RING_NUM_MAX]; /*!< Rx buffer start address for reInitialize. */ + enet_qos_callback_t callback; /*!< Callback function. */ + void *userData; /*!< Callback function parameter.*/ + uint8_t multicastCount[64]; /*!< Multicast collisions counter */ + enet_qos_rx_alloc_callback_t rxBuffAlloc; /*!< Callback to alloc memory, must be provided for zero-copy Rx. */ + enet_qos_rx_free_callback_t rxBuffFree; /*!< Callback to free memory, must be provided for zero-copy Rx. */ +}; + +/*! @brief Defines the frame buffer structure. */ +typedef struct _enet_qos_buffer_struct +{ + void *buffer; /*!< The buffer store the whole or partial frame. */ + uint16_t length; /*!< The byte length of this buffer. */ +} enet_qos_buffer_struct_t; + +/*! @brief Defines the Rx frame error structure. */ +typedef struct _enet_qos_rx_frame_error +{ + bool rxDstAddrFilterErr : 1; /*!< Destination Address Filter Fail. */ + bool rxSrcAddrFilterErr : 1; /*!< SA Address Filter Fail. */ + bool rxDribbleErr : 1; /*!< Dribble error. */ + bool rxReceiveErr : 1; /*!< Receive error. */ + bool rxOverFlowErr : 1; /*!< Receive over flow. */ + bool rxWatchDogErr : 1; /*!< Watch dog timeout. */ + bool rxGaintPacketErr : 1; /*!< Receive gaint packet. */ + bool rxCrcErr : 1; /*!< Receive CRC error. */ +} enet_qos_rx_frame_error_t; + +typedef struct _enet_qos_rx_frame_attribute_struct +{ + bool isTsAvail; /*!< Rx frame timestamp is available or not. */ + enet_qos_ptp_time_t timestamp; /*!< The nanosecond part timestamp of this Rx frame. */ +} enet_qos_rx_frame_attribute_t; + +/*! @brief Defines the Rx frame data structure. */ +typedef struct _enet_qos_rx_frame_struct +{ + enet_qos_buffer_struct_t *rxBuffArray; /*!< Rx frame buffer structure. */ + uint16_t totLen; /*!< Rx frame total length. */ + enet_qos_rx_frame_attribute_t rxAttribute; /*!< Rx frame attribute structure. */ + enet_qos_rx_frame_error_t rxFrameError; /*!< Rx frame error. */ +} enet_qos_rx_frame_struct_t; + +/*! @brief Defines the ENET QOS transfer statistics structure. */ +typedef struct _enet_qos_transfer_stats +{ + uint32_t statsRxFrameCount; /*!< Rx frame number. */ + uint32_t statsRxCrcErr; /*!< Rx frame number with CRC error. */ + uint32_t statsRxAlignErr; /*!< Rx frame number with alignment error. */ + uint32_t statsRxLengthErr; /*!< Rx frame length field doesn't equal to packet size. */ + uint32_t statsRxFifoOverflowErr; /*!< Rx FIFO overflow count. */ + uint32_t statsTxFrameCount; /*!< Tx frame number. */ + uint32_t statsTxFifoUnderRunErr; /*!< Tx FIFO underrun count. */ +} enet_qos_transfer_stats_t; + +/* Typedef for interrupt handler. */ +typedef void (*enet_qos_isr_t)(ENET_QOS_Type *base, enet_qos_handle_t *handle); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to enet clocks for each instance. */ +extern const clock_ip_name_t s_enetqosClock[]; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! + * @brief Set ENET system configuration. + * @note User needs to provide the implementation because the implementation is SoC specific. + * This function set the phy selection and enable clock. + * It should be called before any other ethernet operation. + * + * @param miiMode The MII/RGMII/RMII mode for interface between the phy and Ethernet. + */ +extern void ENET_QOS_SetSYSControl(enet_qos_mii_mode_t miiMode); + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name Initialization and De-initialization + * @{ + */ + +/*! + * @brief Gets the ENET default configuration structure. + * + * The purpose of this API is to get the default ENET configure + * structure for @ref ENET_QOS_Init(). User may use the initialized + * structure unchanged in @ref ENET_QOS_Init(), or modify some fields of the + * structure before calling @ref ENET_QOS_Init(). + * Example: + @code + enet_qos_config_t config; + ENET_QOS_GetDefaultConfig(&config); + @endcode + * @param config The ENET mac controller configuration structure pointer. + */ +void ENET_QOS_GetDefaultConfig(enet_qos_config_t *config); + +/*! + * @brief Initializes the ENET module. + * + * This function initializes it with the ENET basic + * configuration. + * + * @param base ENET peripheral base address. + * @param config ENET mac configuration structure pointer. + * The "enet_qos_config_t" type mac configuration return from ENET_QOS_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * @param macAddr Pointer to ENET mac address array of Ethernet device. This MAC address should be + * provided. + * @param macCount Count of macAddr in the ENET mac address array + * @param refclkSrc_Hz ENET input reference clock. + */ +status_t ENET_QOS_Up( + ENET_QOS_Type *base, const enet_qos_config_t *config, uint8_t *macAddr, uint8_t macCount, uint32_t refclkSrc_Hz); + +/*! + * @brief Initializes the ENET module. + * + * This function ungates the module clock and initializes it with the ENET basic + * configuration. + * + * @param base ENET peripheral base address. + * @param config ENET mac configuration structure pointer. + * The "enet_qos_config_t" type mac configuration return from ENET_QOS_GetDefaultConfig + * can be used directly. It is also possible to verify the Mac configuration using other methods. + * @param macAddr Pointer to ENET mac address array of Ethernet device. This MAC address should be + * provided. + * @param macCount Count of macAddr in the ENET mac address array + * @param refclkSrc_Hz ENET input reference clock. + */ +status_t ENET_QOS_Init( + ENET_QOS_Type *base, const enet_qos_config_t *config, uint8_t *macAddr, uint8_t macCount, uint32_t refclkSrc_Hz); + +/*! + * @brief Stops the ENET module. + + * This function disables the ENET module. + * + * @param base ENET peripheral base address. + */ +void ENET_QOS_Down(ENET_QOS_Type *base); + +/*! + * @brief Deinitializes the ENET module. + + * This function gates the module clock and disables the ENET module. + * + * @param base ENET peripheral base address. + */ +void ENET_QOS_Deinit(ENET_QOS_Type *base); + +/*! + * @brief Get the ENET instance from peripheral base address. + * + * @param base ENET peripheral base address. + * @return ENET instance. + */ +uint32_t ENET_QOS_GetInstance(ENET_QOS_Type *base); + +/*! + * @brief Initialize for all ENET descriptors. + * + * @note This function is do all tx/rx descriptors initialization. Because this API + * read all interrupt registers first and then set the interrupt flag for all descriptors, + * if the interrupt register is set. so the descriptor initialization should be called + * after ENET_QOS_Init(), ENET_QOS_EnableInterrupts() and ENET_QOS_CreateHandle()(if transactional APIs + * are used). + * + * @param base ENET peripheral base address. + * @param config The configuration for ENET. + * @param bufferConfig All buffers configuration. + */ +status_t ENET_QOS_DescriptorInit(ENET_QOS_Type *base, + enet_qos_config_t *config, + enet_qos_buffer_config_t *bufferConfig); + +/*! + * @brief Allocates Rx buffers for all BDs. + * It's used for zero copy Rx. In zero copy Rx case, Rx buffers are dynamic. This function + * will populate initial buffers in all BDs for receiving. Then ENET_QOS_GetRxFrame() is used + * to get Rx frame with zero copy, it will allocate new buffer to replace the buffer in BD taken + * by application application should free those buffers after they're used. + * + * @note This function should be called after ENET_QOS_CreateHandler() and buffer allocating callback + * function should be ready. + * + * @param base ENET_QOS peripheral base address. + * @param handle The ENET_QOS handler structure. This is the same handler pointer used in the ENET_QOS_Init. + */ +status_t ENET_QOS_RxBufferAllocAll(ENET_QOS_Type *base, enet_qos_handle_t *handle); + +/*! + * @brief Frees Rx buffers in all BDs. + * It's used for zero copy Rx. In zero copy Rx case, Rx buffers are dynamic. This function + * will free left buffers in all BDs. + * + * @param base ENET_QOS peripheral base address. + * @param handle The ENET_QOS handler structure. This is the same handler pointer used in the ENET_QOS_Init. + */ +void ENET_QOS_RxBufferFreeAll(ENET_QOS_Type *base, enet_qos_handle_t *handle); + +/*! + * @brief Starts the ENET rx/tx. + * This function enable the tx/rx and starts the rx/tx DMA. + * This shall be set after ENET initialization and before + * starting to receive the data. + * + * @param base ENET peripheral base address. + * @param rxRingNum The number of the used rx rings. It shall not be + * larger than the ENET_QOS_RING_NUM_MAX(2). If the ringNum is set with + * 1, the ring 0 will be used. + * @param txRingNum The number of the used tx rings. It shall not be + * larger than the ENET_QOS_RING_NUM_MAX(2). If the ringNum is set with + * 1, the ring 0 will be used. + * + * @note This must be called after all the ENET initialization. + * And should be called when the ENET receive/transmit is required. + */ +void ENET_QOS_StartRxTx(ENET_QOS_Type *base, uint8_t txRingNum, uint8_t rxRingNum); + +/* @} */ + +/*! + * @name MII interface operation + * @{ + */ + +/*! + * @brief Sets the ENET MII speed and duplex. + * + * This API is provided to dynamically change the speed and duplex for MAC. + * + * @param base ENET peripheral base address. + * @param speed The speed of the RMII mode. + * @param duplex The duplex of the RMII mode. + */ +static inline void ENET_QOS_SetMII(ENET_QOS_Type *base, enet_qos_mii_speed_t speed, enet_qos_mii_duplex_t duplex) +{ + uint32_t reg = base->MAC_CONFIGURATION & ~(ENET_QOS_MAC_CONFIGURATION_DM_MASK | ENET_QOS_MAC_CONFIGURATION_PS_MASK | + ENET_QOS_MAC_CONFIGURATION_FES_MASK); + reg |= ENET_QOS_MAC_CONFIGURATION_DM(duplex) | (uint32_t)speed; + + base->MAC_CONFIGURATION = reg; +} + +/*! + * @brief Sets the ENET SMI(serial management interface)- MII management interface. + * + * @param base ENET peripheral base address. + * @param csrClock_Hz CSR clock frequency in HZ + */ +void ENET_QOS_SetSMI(ENET_QOS_Type *base, uint32_t csrClock_Hz); + +/*! + * @brief Checks if the SMI is busy. + * + * @param base ENET peripheral base address. + * @return The status of MII Busy status. + */ +static inline bool ENET_QOS_IsSMIBusy(ENET_QOS_Type *base) +{ + return ((base->MAC_MDIO_ADDRESS & ENET_QOS_MAC_MDIO_ADDRESS_GB_MASK) != 0U) ? true : false; +} + +/*! + * @brief Reads data from the PHY register through SMI interface. + * + * @param base ENET peripheral base address. + * @return The data read from PHY + */ +static inline uint16_t ENET_QOS_ReadSMIData(ENET_QOS_Type *base) +{ + return (uint16_t)(base->MAC_MDIO_DATA & ENET_QOS_MAC_MDIO_DATA_GD_MASK); +} + +/*! + * @brief Starts an SMI read command. + * It supports MDIO IEEE802.3 Clause 22. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. + */ +void ENET_QOS_StartSMIRead(ENET_QOS_Type *base, uint32_t phyAddr, uint32_t phyReg); + +/*! + * @brief Starts a SMI write command. + * It supports MDIO IEEE802.3 Clause 22. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param phyReg The PHY register. + * @param data The data written to PHY. + */ +void ENET_QOS_StartSMIWrite(ENET_QOS_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data); + +/*! + * @brief Starts a SMI write command. + * It supports MDIO IEEE802.3 Clause 45. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param device The PHY device type. + * @param phyReg The PHY register address. + * @param data The data written to PHY. + */ +void ENET_QOS_StartExtC45SMIWrite( + ENET_QOS_Type *base, uint32_t phyAddr, uint32_t device, uint32_t phyReg, uint32_t data); + +/*! + * @brief Starts a SMI read command. + * It supports MDIO IEEE802.3 Clause 45. + * After send command, user needs to check whether the transmission is over + * with ENET_QOS_IsSMIBusy(). + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param device The PHY device type. + * @param phyReg The PHY register address. + */ +void ENET_QOS_StartExtC45SMIRead(ENET_QOS_Type *base, uint32_t phyAddr, uint32_t device, uint32_t phyReg); +/* @} */ + +/*! + * @name Other basic operation + * @{ + */ + +/*! + * @brief Sets the ENET module Mac address. + * + * @param base ENET peripheral base address. + * @param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + * @param index Configure macAddr to MAC_ADDRESS[index] register. + */ +static inline void ENET_QOS_SetMacAddr(ENET_QOS_Type *base, uint8_t *macAddr, uint8_t index) +{ + uint32_t lowAddress; + uint32_t highAddress; + + assert(macAddr != NULL); + + lowAddress = ((uint32_t)macAddr[3] << 24U) | ((uint32_t)macAddr[2] << 16U) | ((uint32_t)macAddr[1] << 8U) | + ((uint32_t)macAddr[0]); + highAddress = ((uint32_t)macAddr[5] << 8U) | ((uint32_t)macAddr[4]); + /* Set Macaddr, the MAC address registers are configured to be double-synchronized to the MII clock + domains, then the synchronization is triggered only when bits 31:24 (in little-endian mode) + or bits 7:0 (in Big-Endian mode) of the MAC address low register are written to.*/ + base->MAC_ADDRESS[index].HIGH = highAddress | ENET_QOS_HIGH_AE_MASK; + base->MAC_ADDRESS[index].LOW = lowAddress; +} + +/*! + * @brief Gets the ENET module Mac address. + * + * @param base ENET peripheral base address. + * @param macAddr The six-byte Mac address pointer. + * The pointer is allocated by application and input into the API. + * @param index Get macAddr from MAC_ADDRESS[index] register. + */ +void ENET_QOS_GetMacAddr(ENET_QOS_Type *base, uint8_t *macAddr, uint8_t index); + +/*! + * @brief Adds the ENET_QOS device to a multicast group. + * + * @param base ENET_QOS peripheral base address. + * @param address The six-byte multicast group address which is provided by application. + */ +void ENET_QOS_AddMulticastGroup(ENET_QOS_Type *base, uint8_t *address); + +/*! + * @brief Moves the ENET_QOS device from a multicast group. + * + * @param base ENET_QOS peripheral base address. + * @param address The six-byte multicast group address which is provided by application. + */ +void ENET_QOS_LeaveMulticastGroup(ENET_QOS_Type *base, uint8_t *address); + +/*! + * @brief Enable ENET device to accept all multicast frames. + * + * @param base ENET peripheral base address. + */ +static inline void ENET_QOS_AcceptAllMulticast(ENET_QOS_Type *base) +{ + uint32_t reg = base->MAC_PACKET_FILTER; + + base->MAC_PACKET_FILTER = reg | ENET_QOS_MAC_PACKET_FILTER_PM_MASK; +} + +/*! + * @brief ENET device reject to accept all multicast frames. + * + * @param base ENET peripheral base address. + */ +static inline void ENET_QOS_RejectAllMulticast(ENET_QOS_Type *base) +{ + uint32_t reg = base->MAC_PACKET_FILTER; + + base->MAC_PACKET_FILTER = reg & ~ENET_QOS_MAC_PACKET_FILTER_PM_MASK; +} + +/*! + * @brief Set the MAC to enter into power down mode. + * the remote power wake up frame and magic frame can wake up + * the ENET from the power down mode. + * + * @param base ENET peripheral base address. + * @param wakeFilter The wakeFilter provided to configure the wake up frame filter. + * Set the wakeFilter to NULL is not required. But if you have the filter requirement, + * please make sure the wakeFilter pointer shall be eight continuous + * 32-bits configuration. + */ +void ENET_QOS_EnterPowerDown(ENET_QOS_Type *base, uint32_t *wakeFilter); + +/*! + * @brief Set the MAC to exit power down mode. + * Exit from the power down mode and recover to normal work mode. + * + * @param base ENET peripheral base address. + */ +static inline void ENET_QOS_ExitPowerDown(ENET_QOS_Type *base) +{ + /* Clear and status ans reset the power down. */ + base->MAC_PMT_CONTROL_STATUS &= ~ENET_QOS_MAC_PMT_CONTROL_STATUS_PWRDWN_MASK; + + /* Restore the tx which is disabled when enter power down mode. */ + base->DMA_CH[0].DMA_CHX_TX_CTRL |= ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK; + base->DMA_CH[1].DMA_CHX_TX_CTRL |= ENET_QOS_DMA_CHX_TX_CTRL_ST_MASK; + base->MAC_CONFIGURATION |= ENET_QOS_MAC_CONFIGURATION_TE_MASK; +} + +/*! + * @brief Enable/Disable Rx parser,please notice that for enable/disable Rx Parser, + * should better disable Receive first. + * + * @param base ENET_QOS peripheral base address. + * @param enable Enable/Disable Rx parser function + * @retval kStatus_Success Configure rx parser success. + * @retval kStatus_ENET_QOS_Timeout Poll status flag timeout. + */ +status_t ENET_QOS_EnableRxParser(ENET_QOS_Type *base, bool enable); +/* @} */ + +/*! + * @name Interrupts. + * @{ + */ + +/*! + * @brief Enables the ENET DMA and MAC interrupts. + * + * This function enables the ENET interrupt according to the provided mask. The mask + * is a logical OR of enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + * For example, to enable the dma and mac interrupt, do the following. + * @code + * ENET_QOS_EnableInterrupts(ENET, kENET_QOS_DmaRx | kENET_QOS_DmaTx | kENET_QOS_MacPmt); + * @endcode + * + * @param base ENET peripheral base address. + * @param mask ENET interrupts to enable. This is a logical OR of both + * enumeration :: enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + */ +void ENET_QOS_EnableInterrupts(ENET_QOS_Type *base, uint32_t mask); + +/*! + * @brief Disables the ENET DMA and MAC interrupts. + * + * This function disables the ENET interrupt according to the provided mask. The mask + * is a logical OR of enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + * For example, to disable the dma and mac interrupt, do the following. + * @code + * ENET_QOS_DisableInterrupts(ENET, kENET_QOS_DmaRx | kENET_QOS_DmaTx | kENET_QOS_MacPmt); + * @endcode + * + * @param base ENET peripheral base address. + * @param mask ENET interrupts to disables. This is a logical OR of both + * enumeration :: enet_qos_dma_interrupt_enable_t and enet_qos_mac_interrupt_enable_t. + */ +void ENET_QOS_DisableInterrupts(ENET_QOS_Type *base, uint32_t mask); + +/*! + * @brief Gets the ENET DMA interrupt status flag. + * + * @param base ENET peripheral base address. + * @param channel The DMA Channel. Shall not be larger than ENET_QOS_RING_NUM_MAX. + * @return The event status of the interrupt source. This is the logical OR of members + * of the enumeration :: enet_qos_dma_interrupt_enable_t. + */ +static inline uint32_t ENET_QOS_GetDmaInterruptStatus(ENET_QOS_Type *base, uint8_t channel) +{ + return base->DMA_CH[channel].DMA_CHX_STAT; +} + +/*! + * @brief Clear the ENET DMA interrupt status flag. + * + * @param base ENET peripheral base address. + * @param channel The DMA Channel. Shall not be larger than ENET_QOS_RING_NUM_MAX. + * @param mask The interrupt status to be cleared. This is the logical OR of members + * of the enumeration :: enet_qos_dma_interrupt_enable_t. + */ +static inline void ENET_QOS_ClearDmaInterruptStatus(ENET_QOS_Type *base, uint8_t channel, uint32_t mask) +{ + /* Clear the dam interrupt status bit in dma channel interrupt status register. */ + base->DMA_CH[channel].DMA_CHX_STAT = mask; +} + +/*! + * @brief Gets the ENET MAC interrupt status flag. + * + * @param base ENET peripheral base address. + * @return The event status of the interrupt source. + * Use the enum in enet_qos_mac_interrupt_enable_t and right shift + * ENET_QOS_MACINT_ENUM_OFFSET to mask the returned value to get the + * exact interrupt status. + */ +static inline uint32_t ENET_QOS_GetMacInterruptStatus(ENET_QOS_Type *base) +{ + return base->MAC_INTERRUPT_STATUS; +} + +/*! + * @brief Clears the ENET mac interrupt events status flag. + * + * This function clears enabled ENET interrupts according to the provided mask. The mask + * is a logical OR of enumeration members. See the @ref enet_qos_mac_interrupt_enable_t. + * For example, to clear the TX frame interrupt and RX frame interrupt, do the following. + * @code + * ENET_QOS_ClearMacInterruptStatus(ENET, kENET_QOS_MacPmt); + * @endcode + * + * @param base ENET peripheral base address. + * @param mask ENET interrupt source to be cleared. + * This is the logical OR of members of the enumeration :: enet_qos_mac_interrupt_enable_t. + */ +void ENET_QOS_ClearMacInterruptStatus(ENET_QOS_Type *base, uint32_t mask); + +/* @} */ + +/*! + * @name Functional operation. + * @{ + */ + +/*! + * @brief Get the tx descriptor DMA Own flag. + * + * @param txDesc The given tx descriptor. + * @retval True the dma own tx descriptor, false application own tx descriptor. + * + */ +static inline bool ENET_QOS_IsTxDescriptorDmaOwn(enet_qos_tx_bd_struct_t *txDesc) +{ + return ((txDesc->controlStat & ENET_QOS_TXDESCRIP_RD_OWN_MASK) != 0U) ? true : false; +} + +/*! + * @brief Setup a given tx descriptor. + * This function is a low level functional API to setup or prepare + * a given tx descriptor. + * + * @param txDesc The given tx descriptor. + * @param buffer1 The first buffer address in the descriptor. + * @param bytes1 The bytes in the fist buffer. + * @param buffer2 The second buffer address in the descriptor. + * @param bytes2 The bytes in the second buffer. + * @param framelen The length of the frame to be transmitted. + * @param intEnable Interrupt enable flag. + * @param tsEnable The timestamp enable. + * @param flag The flag of this tx descriptor, @ref enet_qos_desc_flag . + * @param slotNum The slot num used for AV only. + * + * @note This must be called after all the ENET initialization. + * And should be called when the ENET receive/transmit is required. + * Transmit buffers are 'zero-copy' buffers, so the buffer must remain in + * memory until the packet has been fully transmitted. The buffers + * should be free or requeued in the transmit interrupt irq handler. + */ +void ENET_QOS_SetupTxDescriptor(enet_qos_tx_bd_struct_t *txDesc, + void *buffer1, + uint32_t bytes1, + void *buffer2, + uint32_t bytes2, + uint32_t framelen, + bool intEnable, + bool tsEnable, + enet_qos_desc_flag flag, + uint8_t slotNum); + +/*! + * @brief Update the tx descriptor tail pointer. + * This function is a low level functional API to update the + * the tx descriptor tail. + * This is called after you setup a new tx descriptor to update + * the tail pointer to make the new descriptor accessible by DMA. + * + * @param base ENET peripheral base address. + * @param channel The tx DMA channel. + * @param txDescTailAddrAlign The new tx tail pointer address. + * + */ +static inline void ENET_QOS_UpdateTxDescriptorTail(ENET_QOS_Type *base, uint8_t channel, uint32_t txDescTailAddrAlign) +{ + base->DMA_CH[channel].DMA_CHX_TXDESC_TAIL_PTR = txDescTailAddrAlign & ~ENET_QOS_ADDR_ALIGNMENT; +} + +/*! + * @brief Update the rx descriptor tail pointer. + * This function is a low level functional API to update the + * the rx descriptor tail. + * This is called after you setup a new rx descriptor to update + * the tail pointer to make the new descriptor accessible by DMA + * and to anouse the rx poll command for DMA. + * + * @param base ENET peripheral base address. + * @param channel The rx DMA channel. + * @param rxDescTailAddrAlign The new rx tail pointer address. + * + */ +static inline void ENET_QOS_UpdateRxDescriptorTail(ENET_QOS_Type *base, uint8_t channel, uint32_t rxDescTailAddrAlign) +{ + base->DMA_CH[channel].DMA_CHX_RXDESC_TAIL_PTR = rxDescTailAddrAlign & ~ENET_QOS_ADDR_ALIGNMENT; +} + +/*! + * @brief Gets the context in the ENET rx descriptor. + * This function is a low level functional API to get the + * the status flag from a given rx descriptor. + * + * @param rxDesc The given rx descriptor. + * @retval The RDES3 regions for write-back format rx buffer descriptor. + * + * @note This must be called after all the ENET initialization. + * And should be called when the ENET receive/transmit is required. + */ +static inline uint32_t ENET_QOS_GetRxDescriptor(enet_qos_rx_bd_struct_t *rxDesc) +{ + assert(rxDesc != NULL); + + return rxDesc->control; +} +/*! + * @brief Updates the buffers and the own status for a given rx descriptor. + * This function is a low level functional API to Updates the + * buffers and the own status for a given rx descriptor. + * + * @param rxDesc The given rx descriptor. + * @param buffer1 The first buffer address in the descriptor. + * @param buffer2 The second buffer address in the descriptor. + * @param intEnable Interrupt enable flag. + * @param doubleBuffEnable The double buffer enable flag. + * + * @note This must be called after all the ENET initialization. + * And should be called when the ENET receive/transmit is required. + */ +void ENET_QOS_UpdateRxDescriptor( + enet_qos_rx_bd_struct_t *rxDesc, void *buffer1, void *buffer2, bool intEnable, bool doubleBuffEnable); + +/*! + * @brief Configure flexible rx parser. + * + * This function is used to configure the flexible rx parser table. + * + * @param base ENET peripheral base address.. + * @param rxpConfig The rx parser configuration pointer. + * @param entryCount The rx parser entry count. + * @retval kStatus_Success Configure rx parser success. + * @retval kStatus_ENET_QOS_Timeout Poll status flag timeout. + */ +status_t ENET_QOS_ConfigureRxParser(ENET_QOS_Type *base, enet_qos_rxp_config_t *rxpConfig, uint16_t entryCount); + +/*! + * @brief Read flexible rx parser configuration at specified index. + * + * This function is used to read flexible rx parser configuration at specified index. + * + * @param base ENET peripheral base address.. + * @param rxpConfig The rx parser configuration pointer. + * @param entryIndex The rx parser entry index to read, start from 0. + * @retval kStatus_Success Configure rx parser success. + * @retval kStatus_ENET_QOS_Timeout Poll status flag timeout. + */ +status_t ENET_QOS_ReadRxParser(ENET_QOS_Type *base, enet_qos_rxp_config_t *rxpConfig, uint16_t entryIndex); + +/*! + * @brief Program Gate Control List. + * + * This function is used to program the Enhanced Scheduled Transmisson. (IEEE802.1Qbv) + * + * @param base ENET peripheral base address.. + * @param gcl Pointer to the Gate Control List structure. + * @param ptpClk_Hz frequency of the PTP clock. + */ +status_t ENET_QOS_EstProgramGcl(ENET_QOS_Type *base, enet_qos_est_gcl_t *gcl, uint32_t ptpClk_Hz); + +/*! + * @brief Read Gate Control List. + * + * This function is used to read the Enhanced Scheduled Transmisson list. (IEEE802.1Qbv) + * + * @param base ENET peripheral base address.. + * @param gcl Pointer to the Gate Control List structure. + * @param listLen length of the provided opList array in gcl structure. + * @param hwList Boolean if True read HW list, false read SW list. + */ +status_t ENET_QOS_EstReadGcl(ENET_QOS_Type *base, enet_qos_est_gcl_t *gcl, uint32_t listLen, bool hwList); + +/*! + * @brief Enable Frame Preemption. + * + * This function is used to enable frame preemption. (IEEE802.1Qbu) + * + * @param base ENET peripheral base address.. + */ +static inline void ENET_QOS_FpeEnable(ENET_QOS_Type *base) +{ + base->MAC_FPE_CTRL_STS |= ENET_QOS_MAC_FPE_CTRL_STS_EFPE_MASK; +} + +/*! + * @brief Disable Frame Preemption. + * + * This function is used to disable frame preemption. (IEEE802.1Qbu) + * + * @param base ENET peripheral base address.. + */ +static inline void ENET_QOS_FpeDisable(ENET_QOS_Type *base) +{ + base->MAC_FPE_CTRL_STS &= ~ENET_QOS_MAC_FPE_CTRL_STS_EFPE_MASK; +} + +/*! + * @brief Configure preemptable transmit queues. + * + * This function is used to configure the preemptable queues. (IEEE802.1Qbu) + * + * @param base ENET peripheral base address.. + * @param queueMask bitmask representing queues to set in preemptable mode. + * The N-th bit represents the queue N. + */ +static inline void ENET_QOS_FpeConfigPreemptable(ENET_QOS_Type *base, uint8_t queueMask) +{ + uint32_t control; + + control = base->MTL_FPE_CTRL_STS & ~ENET_QOS_MTL_FPE_CTRL_STS_PEC_MASK; + control |= ENET_QOS_MTL_FPE_CTRL_STS_PEC(queueMask); + base->MTL_FPE_CTRL_STS = control; +} + +/*! + * @brief Sets the ENET AVB feature. + * + * ENET_QOS AVB feature configuration, set transmit bandwidth. + * This API is called when the AVB feature is required. + * + * @param base ENET_QOS peripheral base address. + * @param config The ENET_QOS AVB feature configuration structure. + * @param queueIndex ENET_QOS queue index. + */ +void ENET_QOS_AVBConfigure(ENET_QOS_Type *base, const enet_qos_cbs_config_t *config, uint8_t queueIndex); + +/*! + * @brief Gets statistical data in transfer. + * + * @param base ENET_QOS peripheral base address. + * @param statistics The statistics structure pointer. + */ +void ENET_QOS_GetStatistics(ENET_QOS_Type *base, enet_qos_transfer_stats_t *statistics); + +/* @} */ + +/*! + * @name Transactional operation + * @{ + */ + +/*! + * @brief Create ENET Handler + * + * This is a transactional API and it's provided to store all data which are needed + * during the whole transactional process. This API should not be used when you use + * functional APIs to do data tx/rx. This is function will store many data/flag for + * transactional use, so all configure API such as ENET_QOS_Init(), ENET_QOS_DescriptorInit(), + * ENET_QOS_EnableInterrupts() etc. + * + * @note as our transactional transmit API use the zero-copy transmit buffer. + * so there are two thing we emphasize here: + * 1. tx buffer free/requeue for application should be done in the tx + * interrupt handler. Please set callback: kENET_QOS_TxIntEvent with tx buffer free/requeue + * process APIs. + * 2. the tx interrupt is forced to open. + * + * @param base ENET peripheral base address. + * @param handle ENET handler. + * @param config ENET configuration. + * @param bufferConfig ENET buffer configuration. + * @param callback The callback function. + * @param userData The application data. + */ +void ENET_QOS_CreateHandler(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + enet_qos_config_t *config, + enet_qos_buffer_config_t *bufferConfig, + enet_qos_callback_t callback, + void *userData); + +/*! + * @brief Gets the size of the read frame. + * This function gets a received frame size from the ENET buffer descriptors. + * @note The FCS of the frame is automatically removed by MAC and the size is the length without the FCS. + * After calling @ref ENET_QOS_GetRxFrameSize, @ref ENET_QOS_ReadFrame() should be called to update the + * receive buffers If the result is not "kStatus_ENET_QOS_RxFrameEmpty". + * + * @param base ENET peripheral base address. + * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_QOS_Init. + * @param length The length of the valid frame received. + * @param channel The DMAC channel for the rx. + * @retval kStatus_ENET_QOS_RxFrameEmpty No frame received. Should not call ENET_QOS_ReadFrame to read frame. + * @retval kStatus_ENET_QOS_RxFrameError Data error happens. @ref ENET_QOS_ReadFrame should be called with NULL data + * and NULL length to update the receive buffers. + * @retval kStatus_Success Receive a frame Successfully then the @ref ENET_QOS_ReadFrame + * should be called with the right data buffer and the captured data length input. + */ +status_t ENET_QOS_GetRxFrameSize(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint32_t *length, uint8_t channel); + +/*! + * @brief Reads a frame from the ENET device. + * This function reads a frame from the ENET DMA descriptors. + * The ENET_QOS_GetRxFrameSize should be used to get the size of the prepared data buffer. + * For example use rx dma channel 0: + * @code + * uint32_t length; + * enet_qos_handle_t g_handle; + * status = ENET_QOS_GetRxFrameSize(&g_handle, &length, 0); + * if (length != 0) + * { + * uint8_t *data = memory allocate interface; + * if (!data) + * { + * ENET_QOS_ReadFrame(ENET, &g_handle, NULL, 0, 0); + * } + * else + * { + * status = ENET_QOS_ReadFrame(ENET, &g_handle, data, length, 0); + * } + * } + * else if (status == kStatus_ENET_QOS_RxFrameError) + * { + * ENET_QOS_ReadFrame(ENET, &g_handle, NULL, 0, 0); + * } + * @endcode + * @param base ENET peripheral base address. + * @param handle The ENET handler structure. This is the same handler pointer used in the ENET_QOS_Init. + * @param data The data buffer provided by user to store the frame which memory size should be at least "length". + * @param length The size of the data buffer which is still the length of the received frame. + * @param channel The rx DMA channel. shall not be larger than 2. + * @param ts Pointer to the structure @ref enet_qos_ptp_time_t to save frame timestamp. + * @return The execute status, successful or failure. + */ +status_t ENET_QOS_ReadFrame(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + uint8_t *data, + uint32_t length, + uint8_t channel, + enet_qos_ptp_time_t *ts); + +/*! + * @brief Transmits an ENET frame. + * @note The CRC is automatically appended to the data. Input the data + * to send without the CRC. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_QOS_Init. + * @param data The data buffer provided by user to be send. + * @param length The length of the data to be send. + * @param channel Channel to send the frame, same with queue index. + * @param isNeedTs True to enable timestamp save for the frame + * @param context pointer to user context to be kept in the tx dirty frame information. + * @retval kStatus_Success Send frame succeed. + * @retval kStatus_ENET_QOS_TxFrameBusy Transmit buffer descriptor is busy under transmission. + * The transmit busy happens when the data send rate is over the MAC capacity. + * The waiting mechanism is recommended to be added after each call return with + * kStatus_ENET_QOS_TxFrameBusy. + */ +status_t ENET_QOS_SendFrame(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + uint8_t *data, + uint32_t length, + uint8_t channel, + bool isNeedTs, + void *context); + +/*! + * @brief Reclaim tx descriptors. + * This function is used to update the tx descriptor status and + * store the tx timestamp when the 1588 feature is enabled. + * This is called by the transmit interrupt IRQ handler after the + * complete of a frame transmission. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_QOS_Init. + * @param channel The tx DMA channel. + * + */ +void ENET_QOS_ReclaimTxDescriptor(ENET_QOS_Type *base, enet_qos_handle_t *handle, uint8_t channel); + +/*! + * @brief The ENET IRQ handler. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. + */ +void ENET_QOS_CommonIRQHandler(ENET_QOS_Type *base, enet_qos_handle_t *handle); + +/*! + * @brief Set the second level IRQ handler, allow user to overwrite the default + * second level weak IRQ handler. + * + * @param base ENET peripheral base address. + * @param ISRHandler The handler to install. + */ +void ENET_QOS_SetISRHandler(ENET_QOS_Type *base, enet_qos_isr_t ISRHandler); + +/* @} */ +/*! + * @name ENET Enhanced function operation + * @{ + */ + +/*! + * @brief Correct the ENET PTP 1588 timer in coarse method. + * + * @param base ENET peripheral base address. + * @param operation The system time operation, refer to "enet_qos_systime_op" + * @param second The correction second. + * @param nanosecond The correction nanosecond. + */ +status_t ENET_QOS_Ptp1588CorrectTimerInCoarse(ENET_QOS_Type *base, + enet_qos_systime_op operation, + uint32_t second, + uint32_t nanosecond); + +/*! + * @brief Correct the ENET PTP 1588 timer in fine method. + * + * + * @param base ENET peripheral base address. + * @param addend The addend value to be set in the fine method + * @note Should take refer to the chapter "System time correction" and + * see the description for the "fine correction method". + */ +status_t ENET_QOS_Ptp1588CorrectTimerInFine(ENET_QOS_Type *base, uint32_t addend); + +/*! + * @brief Get the ENET Time stamp current addend value. + * + * @param base ENET peripheral base address. + * @return The addend value. + */ +static inline uint32_t ENET_QOS_Ptp1588GetAddend(ENET_QOS_Type *base) +{ + return base->MAC_TIMESTAMP_ADDEND; +} + +/*! + * @brief Gets the current ENET time from the PTP 1588 timer without IRQ disable. + * + * @param base ENET peripheral base address. + * @param second The PTP 1588 system timer second. + * @param nanosecond The PTP 1588 system timer nanosecond. + * For the unit of the nanosecond is 1ns. so the nanosecond is the real nanosecond. + */ +void ENET_QOS_Ptp1588GetTimerNoIRQDisable(ENET_QOS_Type *base, uint64_t *second, uint32_t *nanosecond); + +/*! + * @brief Sets the ENET PTP 1588 PPS control. + * All channels operate in flexible PPS output mode. + * + * @param base ENET peripheral base address. + * @param instance The ENET QOS PTP PPS instance. + * @param trgtMode The target time register mode. + * @param cmd The target flexible PPS output control command. + */ +static inline status_t ENET_Ptp1588PpsControl(ENET_QOS_Type *base, + enet_qos_ptp_pps_instance_t instance, + enet_qos_ptp_pps_trgt_mode_t trgtMode, + enet_qos_ptp_pps_cmd_t cmd) +{ + uint32_t reg = 0UL; + uint8_t shift = (uint8_t)instance * 8U; + uint32_t pps_config = ENET_QOS_MAC_PPS_CONTROL_TRGTMODSEL0((uint32_t)trgtMode) | + ENET_QOS_MAC_PPS_CONTROL_PPSCTRL_PPSCMD((uint32_t)cmd); + + reg = base->MAC_PPS_CONTROL; + + /* Make sure CMD field is all zero */ + if ((reg & (0xFUL << shift)) != 0UL) + { + return kStatus_ENET_QOS_PpsBusy; + } + + reg &= ~(0xFFUL << shift); + reg |= (pps_config << shift) | ENET_QOS_MAC_PPS_CONTROL_PPSEN0(1U); + + base->MAC_PPS_CONTROL = reg; + + return kStatus_Success; +} + +/*! + * @brief Sets the ENET OQS PTP 1588 PPS target time registers. + * + * @param base ENET QOS peripheral base address. + * @param instance The ENET QOS PTP PPS instance. + * @param seconds The target seconds. + * @param nanoseconds The target nanoseconds. + */ +status_t ENET_QOS_Ptp1588PpsSetTrgtTime(ENET_QOS_Type *base, + enet_qos_ptp_pps_instance_t instance, + uint32_t seconds, + uint32_t nanoseconds); + +/*! + * @brief Sets the ENET OQS PTP 1588 PPS output signal interval + * + * @param base ENET QOS peripheral base address. + * @param instance The ENET QOS PTP PPS instance. + * @param width Signal Width. It is stored in terms of number of + * units of sub-second increment value. The width value must be + * lesser than interval value. + */ +static inline void ENET_QOS_Ptp1588PpsSetWidth(ENET_QOS_Type *base, + enet_qos_ptp_pps_instance_t instance, + uint32_t width) +{ + uint32_t *mac_pps_width; + + mac_pps_width = (uint32_t *)((uint32_t)&base->MAC_PPS0_WIDTH + 0x10U * (uint32_t)instance); + + *mac_pps_width = ENET_QOS_MAC_PPS0_WIDTH_PPSWIDTH0(width); +} + +/*! + * @brief Sets the ENET OQS PTP 1588 PPS output signal width + * + * @param base ENET QOS peripheral base address. + * @param instance The ENET QOS PTP PPS instance. + * @param interval Signal Interval. It is stored in terms of number of + * units of sub-second increment value. + */ +static inline void ENET_QOS_Ptp1588PpsSetInterval(ENET_QOS_Type *base, + enet_qos_ptp_pps_instance_t instance, + uint32_t interval) +{ + uint32_t *mac_pps_interval; + + mac_pps_interval = (uint32_t *)((uint32_t)&base->MAC_PPS0_INTERVAL + 0x10U * (uint32_t)instance); + + *mac_pps_interval = ENET_QOS_MAC_PPS0_INTERVAL_PPSINT0(interval); +} + +/*! + * @brief Gets the current ENET time from the PTP 1588 timer. + * + * @param base ENET peripheral base address. + * @param second The PTP 1588 system timer second. + * @param nanosecond The PTP 1588 system timer nanosecond. + * For the unit of the nanosecond is 1ns.so the nanosecond is the real nanosecond. + */ +void ENET_QOS_Ptp1588GetTimer(ENET_QOS_Type *base, uint64_t *second, uint32_t *nanosecond); + +/*! + * @brief Gets the time stamp of the transmit frame. + * + * This function is used for PTP stack to get the timestamp captured by the ENET driver. + * + * @param handle The ENET handler pointer.This is the same state pointer used in + * ENET_QOS_Init. + * @param txFrame Input parameter, pointer to @ref enet_qos_frame_info_t for saving read out frame information. + * @param channel Channel for searching the tx frame. + */ +void ENET_QOS_GetTxFrame(enet_qos_handle_t *handle, enet_qos_frame_info_t *txFrame, uint8_t channel); + +/*! + * @brief Receives one frame in specified BD ring with zero copy. + * + * This function will use the user-defined allocate and free callback. Every time application gets one frame through + * this function, driver will allocate new buffers for the BDs whose buffers have been taken by application. + * @note This function will drop current frame and update related BDs as available for DMA if new buffers allocating + * fails. Application must provide a memory pool including at least BD number + 1 buffers(+2 if enable double buffer) + * to make this function work normally. If user calls this function in Rx interrupt handler, be careful that this + * function makes Rx BD ready with allocating new buffer(normal) or updating current BD(out of memory). If there's + * always new Rx frame input, Rx interrupt will be triggered forever. Application need to disable Rx interrupt according + * to specific design in this case. + * + * @param base ENET peripheral base address. + * @param handle The ENET handler pointer. This is the same handler pointer used in the ENET_Init. + * @param rxFrame The received frame information structure provided by user. + * @param channel Channel for searching the rx frame. + * @retval kStatus_Success Succeed to get one frame and allocate new memory for Rx buffer. + * @retval kStatus_ENET_QOS_RxFrameEmpty There's no Rx frame in the BD. + * @retval kStatus_ENET_QOS_RxFrameError There's issue in this receiving. + * @retval kStatus_ENET_QOS_RxFrameDrop There's no new buffer memory for BD, drop this frame. + */ +status_t ENET_QOS_GetRxFrame(ENET_QOS_Type *base, + enet_qos_handle_t *handle, + enet_qos_rx_frame_struct_t *rxFrame, + uint8_t channel); +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_ENET_QOS_H_ */ diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_mdio.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_mdio.h new file mode 100644 index 000000000..fb24b17c6 --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_mdio.h @@ -0,0 +1,128 @@ +/* + * Copyright 2020-2021 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_MDIO_H_ +#define _FSL_MDIO_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the timeout macro. */ +#if defined(MDIO_TIMEOUT_COUNT_NUMBER) && MDIO_TIMEOUT_COUNT_NUMBER +#define MDIO_TIMEOUT_COUNT MDIO_TIMEOUT_COUNT_NUMBER +#endif + +/*! @brief Defines the PHY status. */ +enum _mdio_status +{ + kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 0), /*!< ENET PHY SMI visit timeout. */ +}; + +typedef struct _mdio_operations mdio_operations_t; + +/*! @brief MDIO resource. */ +typedef struct _mdio_resource +{ + void *base; /*!< ENET Ip register base. */ + uint32_t csrClock_Hz; /*!< ENET CSR clock. */ +} mdio_resource_t; + +/*! @brief MDIO handle. */ +typedef struct _mdio_handle +{ + mdio_resource_t resource; + const mdio_operations_t *ops; +} mdio_handle_t; + +/*! @brief Camera receiver operations. */ +struct _mdio_operations +{ + void (*mdioInit)(mdio_handle_t *handle); /*!< MDIO interface init. */ + status_t (*mdioWrite)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t data); /*!< IEEE 802.3 Clause 22 MDIO write data. */ + status_t (*mdioRead)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t *dataPtr); /*!< IEEE 802.3 Clause 22 MDIO read data. */ + status_t (*mdioWriteExt)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t data); /*!< IEEE 802.3 Clause 45 MDIO write data. */ + status_t (*mdioReadExt)(mdio_handle_t *handle, + uint32_t phyAddr, + uint32_t devAddr, + uint32_t *dataPtr); /*!< IEEE 802.3 Clause 45 MDIO read data. */ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif +/*! + * @name MDIO Driver + * @{ + */ + +/*! + * @brief MDIO Write function. This function write data over the SMI to + * the specified MDIO register. This function is called by all MDIO interfaces. + * + * @param handle MDIO device handle. + * @retval kStatus_Success MDIO write success + * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out + */ +static inline void MDIO_Init(mdio_handle_t *handle) +{ + handle->ops->mdioInit(handle); +} + +/*! + * @brief MDIO Write function. This function write data over the SMI to + * the specified MDIO register. This function is called by all MDIO interfaces. + * + * @param handle MDIO device handle. + * @param phyAddr MDIO PHY address handle. + * @param devAddr The PHY device register. + * @param data The data written to the MDIO register. + * @retval kStatus_Success MDIO write success + * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out + */ +static inline status_t MDIO_Write(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t data) +{ + return handle->ops->mdioWrite(handle, phyAddr, devAddr, data); +} + +/*! + * @brief MDIO Read function. This interface read data over the SMI from the + * specified MDIO register. This function is called by all MDIO interfaces. + * + * @param handle MDIO device handle. + * @param phyAddr MDIO PHY address handle. + * @param devAddr The PHY device register. + * @param dataPtr The address to store the data read from the MDIO register. + * @retval kStatus_Success MDIO read success + * @retval kStatus_MDIO_SMIVisitTimeout MDIO SMI visit time out + */ +static inline status_t MDIO_Read(mdio_handle_t *handle, uint32_t phyAddr, uint32_t devAddr, uint32_t *dataPtr) +{ + return handle->ops->mdioRead(handle, phyAddr, devAddr, dataPtr); +} + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_phy.h b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_phy.h new file mode 100644 index 000000000..1bd18016b --- /dev/null +++ b/Ubiquitous/XiZi/board/imxrt1176-sbc/third_party_driver/include/fsl_phy.h @@ -0,0 +1,266 @@ +/* + * Copyright 2020 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_PHY_H_ +#define _FSL_PHY_H_ + +#include "fsl_mdio.h" + +/*! @note The following PHY registers are the IEEE802.3 standard definition, same register and bit field may + have different names in various PHYs, but the feature they represent should be same or very similar. */ + +/*! @brief Defines the IEEE802.3 standard PHY registers. */ +#define PHY_BASICCONTROL_REG 0x00U /*!< The PHY basic control register. */ +#define PHY_BASICSTATUS_REG 0x01U /*!< The PHY basic status register. */ +#define PHY_ID1_REG 0x02U /*!< The PHY ID one register. */ +#define PHY_ID2_REG 0x03U /*!< The PHY ID two register. */ +#define PHY_AUTONEG_ADVERTISE_REG 0x04U /*!< The PHY auto-negotiate advertise register. */ +#define PHY_AUTONEG_LINKPARTNER_REG 0x05U /*!< The PHY auto negotiation link partner ability register. */ +#define PHY_AUTONEG_EXPANSION_REG 0x06U /*!< The PHY auto negotiation expansion register. */ +#define PHY_1000BASET_CONTROL_REG 0x09U /*!< The PHY 1000BASE-T control register. */ +#define PHY_MMD_ACCESS_CONTROL_REG 0x0DU /*!< The PHY MMD access control register. */ +#define PHY_MMD_ACCESS_DATA_REG 0x0EU /*!< The PHY MMD access data register. */ + +/*! @brief Defines the mask flag in basic control register(Address 0x00). */ +#define PHY_BCTL_SPEED1_MASK 0x0040U /*!< The PHY speed bit mask(MSB).*/ +#define PHY_BCTL_ISOLATE_MASK 0x0400U /*!< The PHY isolate mask.*/ +#define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */ +#define PHY_BCTL_RESTART_AUTONEG_MASK 0x0200U /*!< The PHY restart auto negotiation mask. */ +#define PHY_BCTL_AUTONEG_MASK 0x1000U /*!< The PHY auto negotiation bit mask. */ +#define PHY_BCTL_SPEED0_MASK 0x2000U /*!< The PHY speed bit mask(LSB). */ +#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */ +#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */ + +/*! @brief Defines the mask flag in basic status register(Address 0x01). */ +#define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */ +#define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */ +#define PHY_BSTATUS_SPEEDUPLX_MASK 0x001CU /*!< The PHY speed and duplex mask. */ +#define PHY_BSTATUS_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */ + +/*! @brief Defines the mask flag in PHY auto-negotiation advertise register(Address 0x04). */ +#define PHY_100BaseT4_ABILITY_MASK 0x200U /*!< The PHY have the T4 ability. */ +#define PHY_100BASETX_FULLDUPLEX_MASK 0x100U /*!< The PHY has the 100M full duplex ability.*/ +#define PHY_100BASETX_HALFDUPLEX_MASK 0x080U /*!< The PHY has the 100M full duplex ability.*/ +#define PHY_10BASETX_FULLDUPLEX_MASK 0x040U /*!< The PHY has the 10M full duplex ability.*/ +#define PHY_10BASETX_HALFDUPLEX_MASK 0x020U /*!< The PHY has the 10M full duplex ability.*/ +#define PHY_IEEE802_3_SELECTOR_MASK 0x001U /*!< The message type being sent by Auto-Nego.*/ + +/*! @brief Defines the mask flag in the 1000BASE-T control register(Address 0x09). */ +#define PHY_1000BASET_FULLDUPLEX_MASK 0x200U /*!< The PHY has the 1000M full duplex ability.*/ +#define PHY_1000BASET_HALFDUPLEX_MASK 0x100U /*!< The PHY has the 1000M half duplex ability.*/ + +/******************************************************************************* + * Definitions + ******************************************************************************/ +typedef struct _phy_handle phy_handle_t; +/*! @brief Defines the PHY link speed. */ +typedef enum _phy_speed +{ + kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */ + kPHY_Speed100M, /*!< ENET PHY 100M speed. */ + kPHY_Speed1000M /*!< ENET PHY 1000M speed. */ +} phy_speed_t; + +/*! @brief Defines the PHY link duplex. */ +typedef enum _phy_duplex +{ + kPHY_HalfDuplex = 0U, /*!< ENET PHY half duplex. */ + kPHY_FullDuplex /*!< ENET PHY full duplex. */ +} phy_duplex_t; + +/*! @brief Defines the PHY loopback mode. */ +typedef enum _phy_loop +{ + kPHY_LocalLoop = 0U, /*!< ENET PHY local/digital loopback. */ + kPHY_RemoteLoop, /*!< ENET PHY remote loopback. */ + kPHY_ExternalLoop, /*!< ENET PHY external loopback. */ +} phy_loop_t; + +/*! @brief Defines the PHY MMD data access mode. */ +typedef enum _phy_mmd_access_mode +{ + kPHY_MMDAccessNoPostIncrement = (1U << 14), /*!< ENET PHY MMD access data with no address post increment. */ + kPHY_MMDAccessRdWrPostIncrement = + (2U << 14), /*!< ENET PHY MMD access data with Read/Write address post increment. */ + kPHY_MMDAccessWrPostIncrement = (3U << 14), /*!< ENET PHY MMD access data with Write address post increment. */ +} phy_mmd_access_mode_t; + +/*! @brief Defines PHY configuration. */ +typedef struct _phy_config +{ + uint32_t phyAddr; /*!< PHY address. */ + phy_speed_t speed; /*!< PHY speed configuration. */ + phy_duplex_t duplex; /*!< PHY duplex configuration. */ + bool autoNeg; /*!< PHY auto-negotiation, true: enable, false: disable. */ + bool enableEEE; /*!< PHY Energy Efficient Ethernet. */ +} phy_config_t; + +/*! @brief PHY device operations. */ +typedef struct _phy_operations +{ + status_t (*phyInit)(phy_handle_t *handle, const phy_config_t *config); + status_t (*phyWrite)(phy_handle_t *handle, uint32_t phyReg, uint32_t data); + status_t (*phyRead)(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr); + status_t (*getAutoNegoStatus)(phy_handle_t *handle, bool *status); + status_t (*getLinkStatus)(phy_handle_t *handle, bool *status); + status_t (*getLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex); + status_t (*setLinkSpeedDuplex)(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex); + status_t (*enableLoopback)(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable); +} phy_operations_t; + +/*! @brief PHY device handle. */ + +struct _phy_handle +{ + uint32_t phyAddr; /*!< PHY address. */ + mdio_handle_t *mdioHandle; /*!< The MDIO handle used by the phy device, it is specified by device. */ + const phy_operations_t *ops; /*!< The device related operations. */ +}; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize PHY. + * + * @param handle PHY device handle. + * @param config Pointer to structure of phy_config_t. + * @retval kStatus_Success PHY initialization succeeds + * @retval kStatus_Fail PHY initialization fails + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_Init(phy_handle_t *handle, const phy_config_t *config) +{ + return handle->ops->phyInit(handle, config); +} +/*! + * @brief PHY Write function. This function write data over the SMI to + * the specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param data The data written to the PHY register. + * @retval kStatus_Success PHY write success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_Write(phy_handle_t *handle, uint32_t phyReg, uint32_t data) +{ + return handle->ops->phyWrite(handle, phyReg, data); +} + +/*! + * @brief PHY Read function. This interface read data over the SMI from the + * specified PHY register. This function is called by all PHY interfaces. + * + * @param handle PHY device handle. + * @param phyReg The PHY register. + * @param dataPtr The address to store the data read from the PHY register. + * @retval kStatus_Success PHY read success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_Read(phy_handle_t *handle, uint32_t phyReg, uint32_t *dataPtr) +{ + return handle->ops->phyRead(handle, phyReg, dataPtr); +} + +/*! + * @brief Gets the PHY auto-negotiation status. + * + * @param handle PHY device handle. + * @param status The auto-negotiation status of the PHY. + * - true the auto-negotiation is over. + * - false the auto-negotiation is on-going or not started. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_GetAutoNegotiationStatus(phy_handle_t *handle, bool *status) +{ + return handle->ops->getAutoNegoStatus(handle, status); +} + +/*! + * @brief Gets the PHY link status. + * + * @param handle PHY device handle. + * @param status The link up or down status of the PHY. + * - true the link is up. + * - false the link is down. + * @retval kStatus_Success PHY get link status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_GetLinkStatus(phy_handle_t *handle, bool *status) +{ + return handle->ops->getLinkStatus(handle, status); +} + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @brief This function gets the speed and duplex mode of PHY. User can give one of speed + * and duplex address paramter and set the other as NULL if only wants to get one of them. + * + * @param handle PHY device handle. + * @param speed The address of PHY link speed. + * @param duplex The link duplex of PHY. + * @retval kStatus_Success PHY get link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_GetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t *speed, phy_duplex_t *duplex) +{ + return handle->ops->getLinkSpeedDuplex(handle, speed, duplex); +} + +/*! + * @brief Sets the PHY link speed and duplex. + * + * @param handle PHY device handle. + * @param speed Specified PHY link speed. + * @param duplex Specified PHY link duplex. + * @retval kStatus_Success PHY gets status success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_SetLinkSpeedDuplex(phy_handle_t *handle, phy_speed_t speed, phy_duplex_t duplex) +{ + return handle->ops->setLinkSpeedDuplex(handle, speed, duplex); +} + +/*! + * @brief Enable PHY loopcback mode. + * + * @param handle PHY device handle. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * All loopback modes should not be set together, when one loopback mode is set + * another should be disabled. + * @param speed PHY speed for loopback mode. + * @param enable True to enable, false to disable. + * @retval kStatus_Success PHY get link speed and duplex success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + */ +static inline status_t PHY_EnableLoopback(phy_handle_t *handle, phy_loop_t mode, phy_speed_t speed, bool enable) +{ + return handle->ops->enableLoopback(handle, mode, speed, enable); +} + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ +#endif diff --git a/Ubiquitous/XiZi/board/ok1052-c/config.mk b/Ubiquitous/XiZi/board/ok1052-c/config.mk index 920aa07f6..411c25887 100644 --- a/Ubiquitous/XiZi/board/ok1052-c/config.mk +++ b/Ubiquitous/XiZi/board/ok1052-c/config.mk @@ -4,6 +4,15 @@ export CFLAGS := -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -D export AFLAGS := -c -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -x assembler-with-cpp -Wa,-mimplicit-it=thumb -gdwarf-2 ### if use USB function, use special lds file because USB uses ITCM +ifeq ($(CONFIG_LIB_MUSLLIB), y) +export LFLAGS += -nostdlib -nostdinc # -fno-builtin -nodefaultlibs +export LIBCC := -lgcc +export LINK_MUSLLIB := $(KERNEL_ROOT)/lib/musllib/libmusl.a +endif + +ifeq ($(CONFIG_RESOURCES_LWIP), y) +export LINK_LWIP := $(KERNEL_ROOT)/resources/ethernet/LwIP/liblwip.a +endif ifeq ($(CONFIG_BSP_USING_USB),y) export LFLAGS := -mcpu=cortex-m7 -mthumb -ffunction-sections -fdata-sections -Wl,--gc-sections,-Map=XiZi-ok1052-c.map,-cref,-u,Reset_Handler -T $(BSP_ROOT)/link-usb.lds diff --git a/Ubiquitous/XiZi/board/ok1052-c/include/board.h b/Ubiquitous/XiZi/board/ok1052-c/include/board.h index c406861fb..16266b0fa 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/include/board.h +++ b/Ubiquitous/XiZi/board/ok1052-c/include/board.h @@ -35,7 +35,10 @@ Modification: #include "clock_config.h" #include #include + +#ifdef BSP_USING_LWIP #include "enet_ethernetif.h" +#endif extern int heap_start; extern int heap_end; @@ -52,6 +55,8 @@ void InitBoardHardware(void); /*! @brief The board name */ #define BOARD_NAME "IMXRT1050-EVKB" +#define configMAC_ADDR {0x02, 0x12, 0x13, 0x10, 0x15, 0x11} + /* The UART to use for debug messages. */ #define BOARD_DEBUG_UART_TYPE kSerialPort_Uart #define BOARD_DEBUG_UART_BASEADDR (uint32_t) LPUART1 diff --git a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c index 870ed17f3..4560f454a 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c +++ b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/enet_ethernetif.c @@ -62,7 +62,7 @@ //#include "FreeRTOS.h" //#include "event_groups.h" #endif - +#include #include "netif/ethernet.h" #include "enet_ethernetif.h" #include "enet_ethernetif_priv.h" @@ -94,6 +94,19 @@ void enet_delay(void) void Time_Update_LwIP(void) { } +ethernetif_config_t enet_cfg = { + .phyAddress = BOARD_ENET0_PHY_ADDRESS, + .clockName = kCLOCK_CoreSysClk, + .macAddress = configMAC_ADDR, +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + .non_dma_memory = non_dma_memory, +#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ +}; + +void *ethernetif_config_enet_set(uint8_t enet_port) +{ + return (void *)&enet_cfg; +} void ethernetif_clk_init(void) { diff --git a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c index 7f99f8216..0bf50e9c0 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c +++ b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/ethernet/ksz8081/fsl_phy.c @@ -21,6 +21,8 @@ * Definitions ******************************************************************************/ +#define FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE + /*! @brief Defines the timeout macro. */ #define PHY_TIMEOUT_COUNT 100000 diff --git a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/connect_ethernet.h b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/connect_ethernet.h index 376c004fe..12f65358b 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/connect_ethernet.h +++ b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/connect_ethernet.h @@ -21,6 +21,9 @@ #ifndef __CONNECT_ETHERNET_H_ #define __CONNECT_ETHERNET_H_ +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/enet_ethernetif.h b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/enet_ethernetif.h index 8416d75bc..1a8abf2ab 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/enet_ethernetif.h +++ b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/include/enet_ethernetif.h @@ -182,9 +182,12 @@ err_t ethernetif1_init(struct netif *netif); void ethernetif_input( struct netif *netif); void ETH_BSP_Config(void); +void *ethernetif_config_enet_set(uint8_t enet_port); int32 lwip_obtain_semaphore(struct netif *netif); +#define NETIF_ENET0_INIT_FUNC ethernetif0_init + #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.c b/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.c index 491e61240..f01d158d1 100644 --- a/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.c +++ b/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.c @@ -50,6 +50,9 @@ extern int Stm32HwRtcInit(); extern int HwSdioInit(); extern int Stm32HwAdcInit(void); extern int Stm32HwDacInit(void); +#ifdef BSP_USING_LWIP +extern int ETH_BSP_Config(); +#endif static void ClockConfiguration() { @@ -142,6 +145,10 @@ struct InitSequenceDesc _board_init[] = #ifdef BSP_USING_DAC {"hw dac init", Stm32HwDacInit}, #endif +#ifdef BSP_USING_LWIP + {"ETH_BSP", ETH_BSP_Config}, +#endif + { " NONE ",NONE }, }; void InitBoardHardware() diff --git a/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.h b/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.h index c79e60143..33a7777a3 100644 --- a/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.h +++ b/Ubiquitous/XiZi/board/stm32f407-st-discovery/board.h @@ -40,6 +40,8 @@ extern int __stack_end__; extern unsigned int g_service_table_start; extern unsigned int g_service_table_end; +#define configMAC_ADDR {0x02, 0x12, 0x13, 0x10, 0x15, 0x11} + #define STM32_USE_SDIO 0 #define STM32_EXT_SRAM 0 diff --git a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/connect_ethernet.c b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/connect_ethernet.c index eb7a62661..cc12cd8c0 100644 --- a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/connect_ethernet.c +++ b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/connect_ethernet.c @@ -62,7 +62,10 @@ extern int32 s_xSemaphore; /* Private functions ---------------------------------------------------------*/ - +void *ethernetif_config_enet_set(uint8_t enet_port) +{ + return NONE; +} /** * @brief ETH_BSP_Config * @param None diff --git a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/ethernetif.c b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/ethernetif.c index 616cc983d..9c0a910d1 100644 --- a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/ethernetif.c +++ b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/ethernet/ethernetif.c @@ -48,9 +48,9 @@ #include "lwip/mem.h" #include "lwip/pbuf.h" #include "lwip/sys.h" +#include "lwip/timeouts.h" #include "netif/etharp.h" #include "err.h" -#include "ethernetif.h" #include "main.h" #include @@ -101,7 +101,7 @@ extern ETH_DMA_Rx_Frame_infos *DMA_RX_FRAME_infos; -void ethernetif_input( void * pvParameters ); + void LoopGetMacPkg(void * pvParameters); static void arp_timer(void *arg); @@ -140,7 +140,7 @@ void LwIP_Pkt_Handle(struct netif *netif) void Time_Update_LwIP(void) { - LocalTime += MS_PER_SYSTICK_F407; + LocalTime += MS_PER_SYSTICK; } @@ -413,7 +413,7 @@ void LoopGetMacPkg(void * pvParameters) * ERR_MEM if private data couldn't be allocated * any other err_t on error */ -err_t ethernetif_init(struct netif *netif) +err_t ethernetif0_init(struct netif *netif) { LWIP_ASSERT("netif != NULL", (netif != NULL)); diff --git a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/connect_ethernet.h b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/connect_ethernet.h index 25c7ce0ce..28d8a417e 100644 --- a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/connect_ethernet.h +++ b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/connect_ethernet.h @@ -43,6 +43,9 @@ #ifndef __STM32F4x7_ETH_BSP_H #define __STM32F4x7_ETH_BSP_H +#include "hardware_eth.h" +#include "hardware_conf.h" + #ifdef __cplusplus extern "C" { #endif @@ -98,6 +101,7 @@ /* Exported macro ------------------------------------------------------------*/ /* Exported functions ------------------------------------------------------- */ void ETH_BSP_Config(void); +void *ethernetif_config_enet_set(uint8_t enet_port); uint32_t Eth_Link_PHYITConfig(uint16_t PHYAddress); void Eth_Link_EXTIConfig(void); void Eth_Link_ITHandler(unsigned short PHYAddress); diff --git a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/hardware_eth.h b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/hardware_eth.h index 600ed7719..6e94b782b 100644 --- a/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/hardware_eth.h +++ b/Ubiquitous/XiZi/board/stm32f407-st-discovery/third_party_driver/include/hardware_eth.h @@ -30,6 +30,8 @@ /* Includes ------------------------------------------------------------------*/ #include "hardware_eth_conf.h" +#include "err.h" +#include "netif/ethernet.h" /** @addtogroup STM32F4x7_ETH_Driver * @{ @@ -1866,6 +1868,9 @@ void ETH_MMCITConfig(uint32_t ETH_MMC_IT, FunctionalState NewState); ITStatus ETH_GetMMCITStatus(uint32_t ETH_MMC_IT); uint32_t ETH_GetMMCRegister(uint32_t ETH_MMCReg); +void ethernetif_input( void * pvParameters ); +err_t ethernetif0_init(struct netif *netif); +#define NETIF_ENET0_INIT_FUNC ethernetif0_init #ifdef __cplusplus } #endif diff --git a/Ubiquitous/XiZi/board/xidatong-arm32/include/board.h b/Ubiquitous/XiZi/board/xidatong-arm32/include/board.h index a7301a34f..c96c9805f 100755 --- a/Ubiquitous/XiZi/board/xidatong-arm32/include/board.h +++ b/Ubiquitous/XiZi/board/xidatong-arm32/include/board.h @@ -51,6 +51,9 @@ void InitBoardHardware(void); /*! @brief The board name */ #define BOARD_NAME "IMXRT1050" +#define configMAC_ADDR {0x02, 0x12, 0x13, 0x10, 0x15, 0x11} + + #define NVIC_PRIORITYGROUP_0 0x00000007U /*!< 0 bits for pre-emption priority 4 bits for subpriority */ #define NVIC_PRIORITYGROUP_1 0x00000006U /*!< 1 bits for pre-emption priority diff --git a/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/ethernet/enet_ethernetif.c b/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/ethernet/enet_ethernetif.c index 823c76a37..2912af879 100755 --- a/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/ethernet/enet_ethernetif.c +++ b/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/ethernet/enet_ethernetif.c @@ -66,7 +66,7 @@ #include "netif/ethernet.h" #include "enet_ethernetif.h" #include "enet_ethernetif_priv.h" - +#include #include "fsl_enet.h" #include "fsl_phy.h" #include "fsl_gpio.h" @@ -95,6 +95,20 @@ void Time_Update_LwIP(void) { } +ethernetif_config_t enet_cfg = { + .phyAddress = BOARD_ENET0_PHY_ADDRESS, + .clockName = kCLOCK_CoreSysClk, + .macAddress = configMAC_ADDR, +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + .non_dma_memory = non_dma_memory, +#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ +}; + +void *ethernetif_config_enet_set(uint8_t enet_port) +{ + return (void *)&enet_cfg; +} + void ethernetif_clk_init(void) { const clock_enet_pll_config_t config = {.enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1}; diff --git a/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/connect_ethernet.h b/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/connect_ethernet.h index 376c004fe..12f65358b 100755 --- a/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/connect_ethernet.h +++ b/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/connect_ethernet.h @@ -21,6 +21,9 @@ #ifndef __CONNECT_ETHERNET_H_ #define __CONNECT_ETHERNET_H_ +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/enet_ethernetif.h b/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/enet_ethernetif.h index bb97d3348..fc96b93a2 100755 --- a/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/enet_ethernetif.h +++ b/Ubiquitous/XiZi/board/xidatong-arm32/third_party_driver/include/enet_ethernetif.h @@ -182,9 +182,11 @@ err_t ethernetif1_init(struct netif *netif); void ethernetif_input( struct netif *netif); int ETH_BSP_Config(void); - +void *ethernetif_config_enet_set(uint8_t enet_port); int32 lwip_obtain_semaphore(struct netif *netif); +#define NETIF_ENET0_INIT_FUNC ethernetif0_init + #if defined(__cplusplus) } #endif /* __cplusplus */ diff --git a/Ubiquitous/XiZi/path_kernel.mk b/Ubiquitous/XiZi/path_kernel.mk index c6ad6b9ba..1bdebb29e 100755 --- a/Ubiquitous/XiZi/path_kernel.mk +++ b/Ubiquitous/XiZi/path_kernel.mk @@ -289,6 +289,12 @@ KERNELPATHS += \ -I$(BSP_ROOT)/third_party_driver \ -I$(BSP_ROOT)/third_party_driver/include \ -I$(BSP_ROOT)/third_party_driver/CMSIS/Include \ + -I$(BSP_ROOT)/third_party_driver/ethernet \ + -I$(BSP_ROOT)/third_party_driver/ethernet/mdio/enet \ + -I$(BSP_ROOT)/third_party_driver/ethernet/mdio/enet_qos \ + -I$(BSP_ROOT)/third_party_driver/ethernet/phy/ksz8081 \ + -I$(BSP_ROOT)/third_party_driver/ethernet/phy/ksz9131rnx \ + -I$(BSP_ROOT)/third_party_driver/cm7 \ -I$(BSP_ROOT)/xip \ -I$(KERNEL_ROOT)/include \ -I$(KERNEL_ROOT)/resources/include \ diff --git a/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/lwipopts.h b/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/lwipopts.h index 98ec316ab..392168382 100644 --- a/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/lwipopts.h +++ b/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/lwipopts.h @@ -265,7 +265,6 @@ The STM32F4x7 allows computing and verifying the IP, UDP, TCP and ICMP checksums typedef unsigned int nfds_t; #endif -#define FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE #define MEMP_LIB_MALLOC 1 #define MEMP_MEM_MALLOC 1 diff --git a/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.c b/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.c index aed1bda45..68061aea7 100644 --- a/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.c +++ b/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.c @@ -67,12 +67,21 @@ #include "board.h" #include "ethernet.h" -#include "enet_ethernetif.h" +#include "connect_ethernet.h" #include -char lwip_ipaddr[] = {192, 168, 250, 253}; -char lwip_netmask[] = {255, 255, 255, 0}; -char lwip_gwaddr[] = {192, 168, 250, 252}; +char lwip_ipaddr[20] = {192, 168, 131, 77}; +char lwip_netmask[20] = {255, 255, 254, 0}; +char lwip_gwaddr[20] = {192, 168, 131, 23}; + +char lwip_eth0_ipaddr[20] = {192, 168, 131, 77}; +char lwip_eth0_netmask[20] = {255, 255, 254, 0}; +char lwip_eth0_gwaddr[20] = {192, 168, 131, 23}; + +char lwip_eth1_ipaddr[20] = {192, 168, 131, 99}; +char lwip_eth1_netmask[20] = {255, 255, 254, 0}; +char lwip_eth1_gwaddr[20] = {192, 168, 131, 23}; + char lwip_flag = 0; x_ticks_t lwip_sys_now; @@ -389,7 +398,9 @@ void lwip_tcp_init(void) /* USER CODE END 0 */ /* Initilialize the LwIP stack without RTOS */ /* add the network interface (IPv4/IPv6) without RTOS */ - netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, ðernetif0_init, &tcpip_input); +#ifdef NETIF_ENET0_INIT_FUNC + netif_add(&gnetif, &ipaddr, &netmask, &gw, NULL, NETIF_ENET0_INIT_FUNC, &tcpip_input); +#endif /* Registers the default network interface */ netif_set_default(&gnetif); @@ -463,22 +474,12 @@ void lwip_config_input(struct netif *net) } } -void lwip_config_net(char *ip, char *mask, char *gw) +void lwip_config_net(uint8_t enet_port, char *ip, char *mask, char *gw) { -#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) - mem_range_t non_dma_memory[] = NON_DMA_MEMORY_ARRAY; -#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ ip4_addr_t net_ipaddr, net_netmask, net_gw; - ethernetif_config_t cfg = { - .phyAddress = BOARD_ENET0_PHY_ADDRESS, - .clockName = kCLOCK_CoreSysClk, - .macAddress = configMAC_ADDR, -#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) - .non_dma_memory = non_dma_memory, -#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ - }; + char* eth_cfg; - ETH_BSP_Config(); + eth_cfg = ethernetif_config_enet_set(enet_port); if(chk_lwip_bit(LWIP_INIT_FLAG)) { @@ -506,8 +507,18 @@ void lwip_config_net(char *ip, char *mask, char *gw) lwip_init(); - netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, &cfg, ethernetif0_init, + if(0 == enet_port) { +#ifdef NETIF_ENET0_INIT_FUNC + netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, eth_cfg, NETIF_ENET0_INIT_FUNC, ethernet_input); +#endif + } else if (1 == enet_port) { +#ifdef NETIF_ENET1_INIT_FUNC + netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, eth_cfg, NETIF_ENET1_INIT_FUNC, + ethernet_input); +#endif + } + netif_set_default(&gnetif); netif_set_up(&gnetif); @@ -527,22 +538,12 @@ void lwip_config_net(char *ip, char *mask, char *gw) lwip_config_input(&gnetif); } -void lwip_config_tcp(char *ip, char *mask, char *gw) +void lwip_config_tcp(uint8_t enet_port, char *ip, char *mask, char *gw) { -#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) - mem_range_t non_dma_memory[] = NON_DMA_MEMORY_ARRAY; -#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ ip4_addr_t net_ipaddr, net_netmask, net_gw; - ethernetif_config_t cfg = { - .phyAddress = BOARD_ENET0_PHY_ADDRESS, - .clockName = kCLOCK_CoreSysClk, - .macAddress = configMAC_ADDR, -#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) - .non_dma_memory = non_dma_memory, -#endif /* FSL_FEATURE_SOC_LPC_ENET_COUNT */ - }; + char* eth_cfg; - ETH_BSP_Config(); + eth_cfg = ethernetif_config_enet_set(enet_port); if(chk_lwip_bit(LWIP_INIT_FLAG)) { @@ -560,8 +561,17 @@ void lwip_config_tcp(char *ip, char *mask, char *gw) IP4_ADDR(&net_netmask, mask[0], mask[1], mask[2], mask[3]); IP4_ADDR(&net_gw, gw[0], gw[1], gw[2], gw[3]); - netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, &cfg, ethernetif0_init, - tcpip_input); + if(0 == enet_port) { +#ifdef NETIF_ENET0_INIT_FUNC + netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, eth_cfg, NETIF_ENET0_INIT_FUNC, + ethernet_input); +#endif + } else if (1 == enet_port) { +#ifdef NETIF_ENET1_INIT_FUNC + netif_add(&gnetif, &net_ipaddr, &net_netmask, &net_gw, eth_cfg, NETIF_ENET1_INIT_FUNC, + ethernet_input); +#endif + } netif_set_default(&gnetif); netif_set_up(&gnetif); diff --git a/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.h b/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.h index 1a914b4ad..517f5c014 100644 --- a/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.h +++ b/Ubiquitous/XiZi/resources/ethernet/LwIP/arch/sys_arch.h @@ -53,12 +53,13 @@ #define LWIP_LOCAL_PORT 4840 #define LWIP_TARGET_PORT LWIP_LOCAL_PORT -#define LWIP_DEMO_TIMES 3 +#define LWIP_DEMO_TIMES 10 #define LWIP_TASK_STACK_SIZE 4096 #define LWIP_DEMO_TASK_PRIO 20 -/* MAC address configuration. */ -#define configMAC_ADDR {0x02, 0x12, 0x13, 0x10, 0x15, 0x11} +// /* MAC address configuration. */ +// #define configMAC_ADDR {0x02, 0x12, 0x13, 0x10, 0x15, 0x11} +// #define configMAC_ADDR_ETH1 {0x02, 0x12, 0x13, 0x10, 0x15, 0x12} /* USER CODE END 0 */ #define SYS_MBOX_NULL -1 @@ -88,10 +89,19 @@ extern char lwip_flag; extern char lwip_ipaddr[]; extern char lwip_netmask[]; extern char lwip_gwaddr[]; + +extern char lwip_eth0_ipaddr[]; +extern char lwip_eth0_netmask[]; +extern char lwip_eth0_gwaddr[]; + +extern char lwip_eth1_ipaddr[]; +extern char lwip_eth1_netmask[]; +extern char lwip_eth1_gwaddr[]; + extern struct netif gnetif; void lwip_tcp_init(void); -void lwip_config_net(char *ip, char *mask, char *gw); -void lwip_config_tcp(char *ip, char *mask, char *gw); +void lwip_config_net(uint8_t enet_port, char *ip, char *mask, char *gw); +void lwip_config_tcp(uint8_t enet_port, char *ip, char *mask, char *gw); #endif diff --git a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_config_demo.c b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_config_demo.c index f213e6c47..92125e661 100755 --- a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_config_demo.c +++ b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_config_demo.c @@ -24,49 +24,82 @@ #include /******************************************************************************/ - +uint8_t enet_id = 0; static void LwipSetIPTask(void *param) { - lwip_config_net(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + uint8_t enet_port = *(uint8_t *)param; ///< test enet port + printf("lw: [%s] config netport id[%d]\n", __func__, enet_port); + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, lwip_gwaddr); } void LwipSetIPTest(int argc, char *argv[]) { if(argc >= 4) { - lw_print("lw: [%s] ip %s mask %s gw %s\n", __func__, argv[1], argv[2], argv[3]); + printf("lw: [%s] ip %s mask %s gw %s netport %s\n", __func__, argv[1], argv[2], argv[3], argv[4]); sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]); sscanf(argv[2], "%d.%d.%d.%d", &lwip_netmask[0], &lwip_netmask[1], &lwip_netmask[2], &lwip_netmask[3]); sscanf(argv[3], "%d.%d.%d.%d", &lwip_gwaddr[0], &lwip_gwaddr[1], &lwip_gwaddr[2], &lwip_gwaddr[3]); + sscanf(argv[4], "%d", &enet_id); + + if(0 == enet_id) + { + printf("save eth0 info\n"); + memcpy(lwip_eth0_ipaddr, lwip_ipaddr, 20); + memcpy(lwip_eth0_netmask, lwip_netmask, 20); + memcpy(lwip_eth0_gwaddr, lwip_gwaddr, 20); + } + else if(1 == enet_id) + { + printf("save eth1 info\n"); + memcpy(lwip_eth1_ipaddr, lwip_ipaddr, 20); + memcpy(lwip_eth1_netmask, lwip_netmask, 20); + memcpy(lwip_eth1_gwaddr, lwip_gwaddr, 20); + } } else if(argc == 2) { - lw_print("lw: [%s] ipaddr %s\n", __func__, argv[1]); + printf("lw: [%s] set eth0 ipaddr %s \n", __func__, argv[1]); sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]); + memcpy(lwip_eth0_ipaddr, lwip_ipaddr, strlen(lwip_ipaddr)); } - - sys_thread_new("SET ip address", LwipSetIPTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); + sys_thread_new("SET ip address", LwipSetIPTask, &enet_id, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), - setip, LwipSetIPTest, SetIp [IP] [Netmask] [Gateway]); +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(5), + setip, LwipSetIPTest, setip [IP] [Netmask] [Gateway] [port]); void LwipShowIPTask(int argc, char *argv[]) { - char mac_addr[] = configMAC_ADDR; + char mac_addr0[] = configMAC_ADDR; lw_notice("\r\n************************************************\r\n"); lw_notice(" Network Configuration\r\n"); lw_notice("************************************************\r\n"); - lw_notice(" IPv4 Address : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_ipaddr)[0], ((u8_t *)&lwip_ipaddr)[1], - ((u8_t *)&lwip_ipaddr)[2], ((u8_t *)&lwip_ipaddr)[3]); - lw_notice(" IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_netmask)[0], ((u8_t *)&lwip_netmask)[1], - ((u8_t *)&lwip_netmask)[2], ((u8_t *)&lwip_netmask)[3]); - lw_notice(" IPv4 Gateway : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_gwaddr)[0], ((u8_t *)&lwip_gwaddr)[1], - ((u8_t *)&lwip_gwaddr)[2], ((u8_t *)&lwip_gwaddr)[3]); - lw_notice(" MAC Address : %x:%x:%x:%x:%x:%x\r\n", mac_addr[0], mac_addr[1], mac_addr[2], - mac_addr[3], mac_addr[4], mac_addr[5]); + lw_notice(" ETH0 IPv4 Address : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_eth0_ipaddr)[0], ((u8_t *)&lwip_eth0_ipaddr)[1], + ((u8_t *)&lwip_eth0_ipaddr)[2], ((u8_t *)&lwip_eth0_ipaddr)[3]); + lw_notice(" ETH0 IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_eth0_netmask)[0], ((u8_t *)&lwip_eth0_netmask)[1], + ((u8_t *)&lwip_eth0_netmask)[2], ((u8_t *)&lwip_eth0_netmask)[3]); + lw_notice(" ETH0 IPv4 Gateway : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_gwaddr)[0], ((u8_t *)&lwip_eth0_gwaddr)[1], + ((u8_t *)&lwip_eth0_gwaddr)[2], ((u8_t *)&lwip_eth0_gwaddr)[3]); + lw_notice(" ETH0 MAC Address : %x:%x:%x:%x:%x:%x\r\n", mac_addr0[0], mac_addr0[1], mac_addr0[2], + mac_addr0[3], mac_addr0[4], mac_addr0[5]); +#ifdef BOARD_NET_COUNT + if(BOARD_NET_COUNT > 1) + { + char mac_addr1[] = configMAC_ADDR_ETH1; + lw_notice("\r\n"); + lw_notice(" ETH1 IPv4 Address : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_eth1_ipaddr)[0], ((u8_t *)&lwip_eth1_ipaddr)[1], + ((u8_t *)&lwip_eth1_ipaddr)[2], ((u8_t *)&lwip_eth1_ipaddr)[3]); + lw_notice(" ETH1 IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_eth1_netmask)[0], ((u8_t *)&lwip_eth1_netmask)[1], + ((u8_t *)&lwip_eth1_netmask)[2], ((u8_t *)&lwip_eth1_netmask)[3]); + lw_notice(" ETH1 IPv4 Gateway : %u.%u.%u.%u\r\n", ((u8_t *)&lwip_eth1_gwaddr)[0], ((u8_t *)&lwip_eth1_gwaddr)[1], + ((u8_t *)&lwip_eth1_gwaddr)[2], ((u8_t *)&lwip_eth1_gwaddr)[3]); + lw_notice(" ETH1 MAC Address : %x:%x:%x:%x:%x:%x\r\n", mac_addr1[0], mac_addr1[1], mac_addr1[2], + mac_addr1[3], mac_addr1[4], mac_addr1[5]); + } +#endif lw_notice("************************************************\r\n"); } diff --git a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c index eb19af7b0..ea972073d 100755 --- a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c +++ b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_dhcp_demo.c @@ -29,16 +29,12 @@ #include "lwip/dhcp.h" #include "lwip/prot/dhcp.h" #include "netif/ethernet.h" -#include "enet_ethernetif.h" #include +#include +#include #include "board.h" - -#include "pin_mux.h" -#include "clock_config.h" -#include "fsl_gpio.h" -#include "fsl_iomuxc.h" -#include "sys_arch.h" +#include "connect_ethernet.h" #define LWIP_DHCP_TIME 10000 // 10s @@ -123,9 +119,10 @@ void LwipDHCPTest(void) { u32_t dhcp_time; static int flag = 0; + uint8_t enet_port = 0; ///< test enet port 0 char ip_addr[4] = {0, 0, 0, 0}; - lwip_config_net(ip_addr, ip_addr, ip_addr); + lwip_config_net(enet_port, ip_addr, ip_addr, ip_addr); set_lwip_bit(LWIP_PRINT_FLAG); dhcp_start(&gnetif); diff --git a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_ping_demo.c b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_ping_demo.c index c306ceb7d..8393ef828 100755 --- a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_ping_demo.c +++ b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_ping_demo.c @@ -29,15 +29,10 @@ #include "netif/ethernet.h" #include #include "board.h" -#include "pin_mux.h" -#include "clock_config.h" #include #include "connect_ethernet.h" -char test_ip_addr[] = {192, 168, 145, 220}; -char test_net_mask[] = {255, 255, 255, 0}; -char test_gw_addr[] = {192, 168, 145, 1}; ip4_addr_t ping_addr; /******************************************************************************/ @@ -45,17 +40,52 @@ ip4_addr_t ping_addr; void LwipPingTest(int argc, char *argv[]) { int result = 0; + uint8_t enet_port = 0; ///< test enet port 0 if(argc >= 4) { - lw_print("lw: [%s] ip %s mask %s gw %s\n", __func__, argv[1], argv[2], argv[3]); + printf("lw: [%s] ip %s mask %s gw %s for netport %s\n", __func__, argv[1], argv[2], argv[3], argv[4]); sscanf(argv[1], "%d.%d.%d.%d", &lwip_ipaddr[0], &lwip_ipaddr[1], &lwip_ipaddr[2], &lwip_ipaddr[3]); sscanf(argv[2], "%d.%d.%d.%d", &lwip_netmask[0], &lwip_netmask[1], &lwip_netmask[2], &lwip_netmask[3]); sscanf(argv[3], "%d.%d.%d.%d", &lwip_gwaddr[0], &lwip_gwaddr[1], &lwip_gwaddr[2], &lwip_gwaddr[3]); + sscanf(argv[4], "%d", &enet_port); + + if(0 == enet_port) + { + memcpy(lwip_eth0_ipaddr, lwip_ipaddr, strlen(lwip_ipaddr)); + memcpy(lwip_eth0_netmask, lwip_netmask, strlen(lwip_netmask)); + memcpy(lwip_eth0_gwaddr, lwip_gwaddr, strlen(lwip_gwaddr)); + } + if(1 == enet_port) + { + memcpy(lwip_eth1_ipaddr, lwip_ipaddr, strlen(lwip_ipaddr)); + memcpy(lwip_eth1_netmask, lwip_netmask, strlen(lwip_netmask)); + memcpy(lwip_eth1_gwaddr, lwip_gwaddr, strlen(lwip_gwaddr)); + } + } + else if(argc == 3) + { + sscanf(argv[2], "%d", &enet_port); + printf("lw: [%s] gw %s netport %d\n", __func__, argv[1], enet_port); + if(isdigit(argv[1][0])) + { + if(sscanf(argv[1], "%d.%d.%d.%d", &lwip_gwaddr[0], &lwip_gwaddr[1], &lwip_gwaddr[2], &lwip_gwaddr[3]) == EOF) + { + lw_notice("input wrong ip\n"); + return; + } + } +#if (LWIP_DHCP) && (PING_USE_SOCKETS) + else + { + get_url_ip(argv[1]); + return; + } +#endif } else if(argc == 2) { - lw_print("lw: [%s] gw %s\n", __func__, argv[1]); + printf("lw: [%s] gw %s\n", __func__, argv[1]); if(isdigit(argv[1][0])) { if(sscanf(argv[1], "%d.%d.%d.%d", &lwip_gwaddr[0], &lwip_gwaddr[1], &lwip_gwaddr[2], &lwip_gwaddr[3]) == EOF) @@ -73,14 +103,14 @@ void LwipPingTest(int argc, char *argv[]) #endif } - lw_print("lw: [%s] argc %d\n", __func__, argc); + printf("lw: [%s] argc %d\n", __func__, argc); IP4_ADDR(&ping_addr, lwip_gwaddr[0], lwip_gwaddr[1], lwip_gwaddr[2], lwip_gwaddr[3]); - lwip_config_net(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, lwip_gwaddr); ping_init(&ping_addr); } -SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3), - ping, LwipPingTest, ping [IP] 3 times); +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(5), + ping, LwipPingTest, ping [IP] 10 times); #endif diff --git a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_tcp_demo.c b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_tcp_demo.c index 7db24051d..08066a302 100755 --- a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_tcp_demo.c +++ b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_tcp_demo.c @@ -70,6 +70,7 @@ static void LwipTcpSendTask(void *arg) void LwipTcpSendTest(int argc, char *argv[]) { LwipTcpSocketParamType param; + uint8_t enet_port = 0; memset(tcp_demo_msg, 0, LWIP_TEST_MSG_SIZE); if(argc >= 2) { @@ -89,7 +90,7 @@ void LwipTcpSendTest(int argc, char *argv[]) } } lw_notice("get ipaddr %d.%d.%d.%d:%d\n", tcp_demo_ip[0], tcp_demo_ip[1], tcp_demo_ip[2], tcp_demo_ip[3], tcp_demo_port); - lwip_config_tcp(lwip_ipaddr, lwip_netmask, tcp_demo_ip); + lwip_config_tcp(enet_port, lwip_ipaddr, lwip_netmask, tcp_demo_ip); memcpy(param.ip, tcp_demo_ip, 4); param.port = tcp_demo_port; @@ -104,7 +105,9 @@ SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | void LwipTcpRecvTest(void) { - lwip_config_net(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + uint8_t enet_port = 0; ///< test enet port 0 + + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, lwip_gwaddr); tcpecho_raw_init(); } diff --git a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_udp_demo.c b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_udp_demo.c index c84ae90f3..fe41771df 100755 --- a/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_udp_demo.c +++ b/Ubiquitous/XiZi/resources/ethernet/cmd_lwip/lwip_udp_demo.c @@ -75,6 +75,7 @@ static void LwipUDPSendTask(void *arg) void *LwipUdpSendTest(int argc, char *argv[]) { + uint8_t enet_port = 0; ///< test enet port 0 memset(udp_demo_msg, 0, sizeof(udp_demo_msg)); if(argc == 1) @@ -94,7 +95,7 @@ void *LwipUdpSendTest(int argc, char *argv[]) lw_print("lw: [%s] gw %d.%d.%d.%d\n", __func__, udp_demo_ip[0], udp_demo_ip[1], udp_demo_ip[2], udp_demo_ip[3]); - lwip_config_net(lwip_ipaddr, lwip_netmask, udp_demo_ip); + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, udp_demo_ip); sys_thread_new("udp send", LwipUDPSendTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO); } @@ -140,8 +141,9 @@ static void LwipUdpRecvTask(void *arg, struct udp_pcb *upcb, struct pbuf *p, void LwipUdpRecvTest(void) { err_t err; + uint8_t enet_port = 0; ///< test enet port 0 - lwip_config_net(lwip_ipaddr, lwip_netmask, lwip_gwaddr); + lwip_config_net(enet_port, lwip_ipaddr, lwip_netmask, lwip_gwaddr); udpecho_raw_pcb = udp_new_ip_type(IPADDR_TYPE_ANY); if (udpecho_raw_pcb == NULL)