From 79b417f1019f2a357c9f43a47570c1f9047d4c3b Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Wed, 23 Mar 2022 10:12:33 +0800 Subject: [PATCH 1/5] delete useless KPrintf in ok1052-c and xidatong board --- .../third_party_driver/gpio/connect_gpio.c | 2 - .../third_party_driver/gpio/connect_gpio.c | 2 - .../board/xidatong/xip/fsl_flexspi_nor_boot.c | 70 ------------------- .../XiZi/kernel/kernel_test/test_ch438.c | 2 +- 4 files changed, 1 insertion(+), 75 deletions(-) diff --git a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c index 3032b282e..2bbb15f76 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c +++ b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c @@ -412,7 +412,6 @@ static uint32 Imxrt1052PinConfigure(struct PinParam *param) struct PinIndex pin_index; - KPrintf("Imxrt1052PinConfigure\n"); if (GetPin(&pin_index, param->pin) < 0) { return ERROR; } @@ -420,7 +419,6 @@ static uint32 Imxrt1052PinConfigure(struct PinParam *param) switch(param->cmd) { case GPIO_CONFIG_MODE: - KPrintf("GpioConfigMode %u\n", param->pin); GpioConfigMode(param->mode, &pin_index, param->pin); break; case GPIO_IRQ_REGISTER: diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c index 4e74fb5cb..58b0ca17a 100755 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c @@ -412,7 +412,6 @@ static uint32 Imxrt1052PinConfigure(struct PinParam *param) struct PinIndex pin_index; - KPrintf("Imxrt1052PinConfigure\n"); if (GetPin(&pin_index, param->pin) < 0) { return ERROR; } @@ -420,7 +419,6 @@ static uint32 Imxrt1052PinConfigure(struct PinParam *param) switch(param->cmd) { case GPIO_CONFIG_MODE: - KPrintf("GpioConfigMode %u\n", param->pin); GpioConfigMode(param->mode, &pin_index, param->pin); break; case GPIO_IRQ_REGISTER: diff --git a/Ubiquitous/XiZi/board/xidatong/xip/fsl_flexspi_nor_boot.c b/Ubiquitous/XiZi/board/xidatong/xip/fsl_flexspi_nor_boot.c index 052813ed6..503d56845 100644 --- a/Ubiquitous/XiZi/board/xidatong/xip/fsl_flexspi_nor_boot.c +++ b/Ubiquitous/XiZi/board/xidatong/xip/fsl_flexspi_nor_boot.c @@ -72,76 +72,6 @@ const BOOT_DATA_T boot_data = { #elif defined(__ICCARM__) #pragma location=".boot_hdr.dcd_data" #endif -//const uint8_t dcd_sdram[1044] = { -///*0000*/ 0xD2, 0x04, 0x14, 0x41, 0xCC, 0x02, 0xF4, 0x04, 0x40, 0x0F, 0xC0, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, -///*0010*/ 0x40, 0x0F, 0xC0, 0x6C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, -///*0020*/ 0x40, 0x0F, 0xC0, 0x74, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, -///*0030*/ 0x40, 0x0F, 0xC0, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, -///*0040*/ 0x40, 0x0D, 0x80, 0x30, 0x00, 0x00, 0x20, 0x01, 0x40, 0x0D, 0x81, 0x00, 0x00, 0x1D, 0x00, 0x00, -///*0050*/ 0x40, 0x0F, 0xC0, 0x14, 0x00, 0x09, 0x83, 0x40, 0x40, 0x1F, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, -///*0060*/ 0x40, 0x1F, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x00, -///*0070*/ 0x40, 0x1F, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, -///*0080*/ 0x40, 0x1F, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, -///*0090*/ 0x40, 0x1F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, -///*00a0*/ 0x40, 0x1F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x3C, 0x00, 0x00, 0x00, 0x00, -///*00b0*/ 0x40, 0x1F, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, -///*00c0*/ 0x40, 0x1F, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x4C, 0x00, 0x00, 0x00, 0x00, -///*00d0*/ 0x40, 0x1F, 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, -///*00e0*/ 0x40, 0x1F, 0x80, 0x58, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x5C, 0x00, 0x00, 0x00, 0x00, -///*00f0*/ 0x40, 0x1F, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x64, 0x00, 0x00, 0x00, 0x00, -///*0100*/ 0x40, 0x1F, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x6C, 0x00, 0x00, 0x00, 0x00, -///*0110*/ 0x40, 0x1F, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x74, 0x00, 0x00, 0x00, 0x00, -///*0120*/ 0x40, 0x1F, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x7C, 0x00, 0x00, 0x00, 0x00, -///*0130*/ 0x40, 0x1F, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x84, 0x00, 0x00, 0x00, 0x00, -///*0140*/ 0x40, 0x1F, 0x80, 0x88, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x8C, 0x00, 0x00, 0x00, 0x00, -///*0150*/ 0x40, 0x1F, 0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x94, 0x00, 0x00, 0x00, 0x00, -///*0160*/ 0x40, 0x1F, 0x80, 0x98, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x9C, 0x00, 0x00, 0x00, 0x00, -///*0170*/ 0x40, 0x1F, 0x80, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA4, 0x00, 0x00, 0x00, 0x00, -///*0180*/ 0x40, 0x1F, 0x80, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xAC, 0x00, 0x00, 0x00, 0x00, -///*0190*/ 0x40, 0x1F, 0x80, 0xB0, 0x00, 0x00, 0x00, 0x10, 0x40, 0x1F, 0x80, 0xB4, 0x00, 0x00, 0x00, 0x00, -///*01a0*/ 0x40, 0x1F, 0x80, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x82, 0x04, 0x00, 0x00, 0x00, 0xF1, -///*01b0*/ 0x40, 0x1F, 0x82, 0x08, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x0C, 0x00, 0x00, 0x00, 0xF1, -///*01c0*/ 0x40, 0x1F, 0x82, 0x10, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x14, 0x00, 0x00, 0x00, 0xF1, -///*01d0*/ 0x40, 0x1F, 0x82, 0x18, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x1C, 0x00, 0x00, 0x00, 0xF1, -///*01e0*/ 0x40, 0x1F, 0x82, 0x20, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x24, 0x00, 0x00, 0x00, 0xF1, -///*01f0*/ 0x40, 0x1F, 0x82, 0x28, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x2C, 0x00, 0x00, 0x00, 0xF1, -///*0200*/ 0x40, 0x1F, 0x82, 0x30, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x34, 0x00, 0x00, 0x00, 0xF1, -///*0210*/ 0x40, 0x1F, 0x82, 0x38, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x3C, 0x00, 0x00, 0x00, 0xF1, -///*0220*/ 0x40, 0x1F, 0x82, 0x40, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x44, 0x00, 0x00, 0x00, 0xF1, -///*0230*/ 0x40, 0x1F, 0x82, 0x48, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x4C, 0x00, 0x00, 0x00, 0xF1, -///*0240*/ 0x40, 0x1F, 0x82, 0x50, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x54, 0x00, 0x00, 0x00, 0xF1, -///*0250*/ 0x40, 0x1F, 0x82, 0x58, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x5C, 0x00, 0x00, 0x00, 0xF1, -///*0260*/ 0x40, 0x1F, 0x82, 0x60, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x64, 0x00, 0x00, 0x00, 0xF1, -///*0270*/ 0x40, 0x1F, 0x82, 0x68, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x6C, 0x00, 0x00, 0x00, 0xF1, -///*0280*/ 0x40, 0x1F, 0x82, 0x70, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x74, 0x00, 0x00, 0x00, 0xF1, -///*0290*/ 0x40, 0x1F, 0x82, 0x78, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x7C, 0x00, 0x00, 0x00, 0xF1, -///*02a0*/ 0x40, 0x1F, 0x82, 0x80, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x84, 0x00, 0x00, 0x00, 0xF1, -///*02b0*/ 0x40, 0x1F, 0x82, 0x88, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x8C, 0x00, 0x00, 0x00, 0xF1, -///*02c0*/ 0x40, 0x1F, 0x82, 0x90, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x94, 0x00, 0x00, 0x00, 0xF1, -///*02d0*/ 0x40, 0x1F, 0x82, 0x98, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x9C, 0x00, 0x00, 0x00, 0xF1, -///*02e0*/ 0x40, 0x1F, 0x82, 0xA0, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0xA4, 0x00, 0x00, 0x00, 0xF1, -///*02f0*/ 0x40, 0x1F, 0x82, 0xA8, 0x00, 0x00, 0x00, 0xF1, 0xCC, 0x00, 0x0C, 0x14, 0x40, 0x2F, 0x00, 0x00, -///*0300*/ 0x00, 0x00, 0x00, 0x02, 0xCC, 0x00, 0x9C, 0x04, 0x40, 0x2F, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, -///*0310*/ 0x40, 0x2F, 0x00, 0x08, 0x00, 0x03, 0x05, 0x24, 0x40, 0x2F, 0x00, 0x0C, 0x06, 0x03, 0x05, 0x24, -///*0320*/ 0x40, 0x2F, 0x00, 0x10, 0x80, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x14, 0x90, 0x00, 0x00, 0x21, -///*0330*/ 0x40, 0x2F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x40, 0x2F, 0x00, 0x40, 0x00, 0x00, 0x0B, 0x27, -///*0340*/ 0x40, 0x2F, 0x00, 0x44, 0x00, 0x10, 0x01, 0x00, 0x40, 0x2F, 0x00, 0x48, 0x00, 0x02, 0x02, 0x01, -///*0350*/ 0x40, 0x2F, 0x00, 0x4C, 0x08, 0x19, 0x3D, 0x0E, 0x40, 0x2F, 0x00, 0x74, 0x00, 0x65, 0x29, 0x22, -///*0360*/ 0x40, 0x2F, 0x00, 0x78, 0x00, 0x01, 0x09, 0x20, 0x40, 0x2F, 0x00, 0x7C, 0x50, 0x21, 0x0A, 0x08, -///*0370*/ 0x40, 0x2F, 0x00, 0x80, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x84, 0x00, 0x88, 0x88, 0x88, -///*0380*/ 0x40, 0x2F, 0x00, 0x94, 0x00, 0x00, 0x00, 0x02, 0x40, 0x2F, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, -///*0390*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0F, -///*03a0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04, -///*03b0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C, -///*03c0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04, -///*03d0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C, -///*03e0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x1C, 0x04, -///*03f0*/ 0x40, 0x2F, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x22, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, -///*0400*/ 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0A, 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, -///*0410*/ 0x00, 0x00, 0x00, 0x01, -//}; - - const uint8_t dcd_sdram[1072] = { /*0000*/ 0xD2, diff --git a/Ubiquitous/XiZi/kernel/kernel_test/test_ch438.c b/Ubiquitous/XiZi/kernel/kernel_test/test_ch438.c index 7802334f4..a63a7e54e 100644 --- a/Ubiquitous/XiZi/kernel/kernel_test/test_ch438.c +++ b/Ubiquitous/XiZi/kernel/kernel_test/test_ch438.c @@ -12,7 +12,7 @@ /** * @file TestCh438.c -* @brief support to test ch438 function +* @brief support to test ch438 function, only support aiit_arm32_board and aiit_riscv64-board * @version 1.0 * @author AIIT XUOS Lab * @date 2021-04-24 From 61aff201a6b8ab6d21f941dc580ad0028f0e9238 Mon Sep 17 00:00:00 2001 From: chunyexixiaoyu <834670833@qq.com> Date: Wed, 23 Mar 2022 14:02:30 +0800 Subject: [PATCH 2/5] Ubiquitous/RT_Thread/:add xidatong bsp 1.mdk keil project is supported. 2.gcc is supported. 3.boot image can be configured to be selected or not,if you use mdk keil,please select xip boot image 4. bin and elf files can be load by NXP-MCUBootUtility.exe. --- .../RT_Thread/aiit_board/xidatong/.config | 339 +++++ .../RT_Thread/aiit_board/xidatong/Kconfig | 29 + .../RT_Thread/aiit_board/xidatong/README.md | 121 ++ .../RT_Thread/aiit_board/xidatong/SConscript | 14 + .../RT_Thread/aiit_board/xidatong/SConstruct | 85 ++ .../xidatong/applications/SConscript | 17 + .../aiit_board/xidatong/applications/main.c | 50 + .../aiit_board/xidatong/board/Kconfig | 216 +++ .../board/MCUX_Config/MCUX_Config.mex | 468 +++++++ .../xidatong/board/MCUX_Config/clock_config.c | 465 +++++++ .../xidatong/board/MCUX_Config/clock_config.h | 66 + .../xidatong/board/MCUX_Config/pin_mux.c | 691 ++++++++++ .../xidatong/board/MCUX_Config/pin_mux.h | 75 + .../xidatong/board/MIMXRT_QSPIFLASH.FLM | Bin 0 -> 1353716 bytes .../aiit_board/xidatong/board/SConscript | 17 + .../aiit_board/xidatong/board/board.c | 142 ++ .../aiit_board/xidatong/board/board.h | 42 + .../xidatong/board/linker_scripts/link.icf | 95 ++ .../xidatong/board/linker_scripts/link.lds | 276 ++++ .../xidatong/board/linker_scripts/link.sct | 134 ++ .../xidatong/board/ports/sdram_port.h | 49 + .../aiit_board/xidatong/project.uvoptx | 177 +++ .../aiit_board/xidatong/project.uvprojx | 987 +++++++++++++ .../RT_Thread/aiit_board/xidatong/rtconfig.h | 194 +++ .../RT_Thread/aiit_board/xidatong/rtconfig.py | 162 +++ .../aiit_board/xidatong/template.uvoptx | 177 +++ .../aiit_board/xidatong/template.uvprojx | 391 ++++++ .../aiit_board/xidatong/xip/SConscript | 20 + .../xidatong/xip/fsl_flexspi_nor_boot.c | 1219 +++++++++++++++++ .../xidatong/xip/fsl_flexspi_nor_boot.h | 123 ++ .../xidatong/xip/fsl_flexspi_nor_flash.c | 88 ++ .../xidatong/xip/fsl_flexspi_nor_flash.h | 303 ++++ 32 files changed, 7232 insertions(+) create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/.config create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/Kconfig create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/README.md create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/SConscript create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/SConstruct create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/applications/SConscript create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/applications/main.c create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/Kconfig create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/MCUX_Config.mex create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.c create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.h create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.c create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.h create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/MIMXRT_QSPIFLASH.FLM create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/SConscript create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/board.c create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/board.h create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.icf create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.lds create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.sct create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/board/ports/sdram_port.h create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvoptx create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvprojx create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.h create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.py create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvoptx create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvprojx create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/xip/SConscript create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.c create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.h create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.c create mode 100644 Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.h diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/.config b/Ubiquitous/RT_Thread/aiit_board/xidatong/.config new file mode 100644 index 000000000..409076860 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/.config @@ -0,0 +1,339 @@ +# +# Automatically generated file; DO NOT EDIT. +# RT-Thread Configuration +# +CONFIG_ROOT_DIR="../../../.." +CONFIG_BSP_DIR="." +CONFIG_RT_Thread_DIR="../.." +CONFIG_RTT_DIR="../../rt-thread" + +# +# RT-Thread Kernel +# +CONFIG_RT_NAME_MAX=8 +# CONFIG_RT_USING_BIG_ENDIAN is not set +# CONFIG_RT_USING_ARCH_DATA_TYPE is not set +# CONFIG_RT_USING_SMP is not set +CONFIG_RT_ALIGN_SIZE=4 +# CONFIG_RT_THREAD_PRIORITY_8 is not set +CONFIG_RT_THREAD_PRIORITY_32=y +# CONFIG_RT_THREAD_PRIORITY_256 is not set +CONFIG_RT_THREAD_PRIORITY_MAX=32 +CONFIG_RT_TICK_PER_SECOND=100 +CONFIG_RT_USING_OVERFLOW_CHECK=y +CONFIG_RT_USING_HOOK=y +CONFIG_RT_USING_IDLE_HOOK=y +CONFIG_RT_IDLE_HOOK_LIST_SIZE=4 +CONFIG_IDLE_THREAD_STACK_SIZE=256 +# CONFIG_RT_USING_TIMER_SOFT is not set + +# +# kservice optimization +# +CONFIG_RT_KSERVICE_USING_STDLIB=y +# CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set +# CONFIG_RT_USING_ASM_MEMCPY is not set +CONFIG_RT_DEBUG=y +CONFIG_RT_DEBUG_COLOR=y +# CONFIG_RT_DEBUG_INIT_CONFIG is not set +# CONFIG_RT_DEBUG_THREAD_CONFIG is not set +# CONFIG_RT_DEBUG_SCHEDULER_CONFIG is not set +# CONFIG_RT_DEBUG_IPC_CONFIG is not set +# CONFIG_RT_DEBUG_TIMER_CONFIG is not set +# CONFIG_RT_DEBUG_IRQ_CONFIG is not set +# CONFIG_RT_DEBUG_MEM_CONFIG is not set +# CONFIG_RT_DEBUG_SLAB_CONFIG is not set +# CONFIG_RT_DEBUG_MEMHEAP_CONFIG is not set +# CONFIG_RT_DEBUG_MODULE_CONFIG is not set + +# +# Inter-Thread communication +# +CONFIG_RT_USING_SEMAPHORE=y +CONFIG_RT_USING_MUTEX=y +CONFIG_RT_USING_EVENT=y +CONFIG_RT_USING_MAILBOX=y +CONFIG_RT_USING_MESSAGEQUEUE=y +# CONFIG_RT_USING_SIGNALS is not set + +# +# Memory Management +# +CONFIG_RT_USING_MEMPOOL=y +CONFIG_RT_USING_MEMHEAP=y +CONFIG_RT_USING_MEMHEAP_AUTO_BINDING=y +# CONFIG_RT_USING_NOHEAP is not set +# CONFIG_RT_USING_SMALL_MEM is not set +# CONFIG_RT_USING_SLAB is not set +CONFIG_RT_USING_MEMHEAP_AS_HEAP=y +# CONFIG_RT_USING_USERHEAP is not set +# CONFIG_RT_USING_MEMTRACE is not set +CONFIG_RT_USING_HEAP=y + +# +# Kernel Device Object +# +CONFIG_RT_USING_DEVICE=y +# CONFIG_RT_USING_DEVICE_OPS is not set +# CONFIG_RT_USING_INTERRUPT_INFO is not set +CONFIG_RT_USING_CONSOLE=y +CONFIG_RT_CONSOLEBUF_SIZE=128 +CONFIG_RT_CONSOLE_DEVICE_NAME="uart1" +# CONFIG_RT_PRINTF_LONGLONG is not set +CONFIG_RT_VER_NUM=0x40004 +# CONFIG_RT_USING_CPU_FFS is not set +# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set + +# +# RT-Thread Components +# +CONFIG_RT_USING_COMPONENTS_INIT=y +CONFIG_RT_USING_USER_MAIN=y +CONFIG_RT_MAIN_THREAD_STACK_SIZE=2048 +CONFIG_RT_MAIN_THREAD_PRIORITY=10 + +# +# C++ features +# +# CONFIG_RT_USING_CPLUSPLUS is not set + +# +# Command shell +# +CONFIG_RT_USING_FINSH=y +CONFIG_RT_USING_MSH=y +CONFIG_FINSH_USING_MSH=y +CONFIG_FINSH_THREAD_NAME="tshell" +CONFIG_FINSH_THREAD_PRIORITY=20 +CONFIG_FINSH_THREAD_STACK_SIZE=4096 +CONFIG_FINSH_USING_HISTORY=y +CONFIG_FINSH_HISTORY_LINES=5 +CONFIG_FINSH_USING_SYMTAB=y +CONFIG_FINSH_CMD_SIZE=80 +CONFIG_MSH_USING_BUILT_IN_COMMANDS=y +CONFIG_FINSH_USING_DESCRIPTION=y +# CONFIG_FINSH_ECHO_DISABLE_DEFAULT is not set +# CONFIG_FINSH_USING_AUTH is not set +CONFIG_FINSH_ARG_MAX=10 + +# +# Device virtual file system +# +CONFIG_RT_USING_DFS=y +CONFIG_DFS_USING_WORKDIR=y +CONFIG_DFS_FILESYSTEMS_MAX=4 +CONFIG_DFS_FILESYSTEM_TYPES_MAX=4 +CONFIG_DFS_FD_MAX=16 +# CONFIG_RT_USING_DFS_MNTTABLE is not set +# CONFIG_RT_USING_DFS_ELMFAT is not set +CONFIG_RT_USING_DFS_DEVFS=y +# CONFIG_RT_USING_DFS_ROMFS is not set +# CONFIG_RT_USING_DFS_RAMFS is not set + +# +# Device Drivers +# +CONFIG_RT_USING_DEVICE_IPC=y +CONFIG_RT_PIPE_BUFSZ=512 +# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set +CONFIG_RT_USING_SERIAL=y +CONFIG_RT_USING_SERIAL_V1=y +# CONFIG_RT_USING_SERIAL_V2 is not set +CONFIG_RT_SERIAL_USING_DMA=y +CONFIG_RT_SERIAL_RB_BUFSZ=64 +# CONFIG_RT_USING_CAN is not set +# CONFIG_RT_USING_HWTIMER is not set +CONFIG_RT_USING_CPUTIME=y +# CONFIG_RT_USING_I2C is not set +# CONFIG_RT_USING_PHY is not set +CONFIG_RT_USING_PIN=y +# CONFIG_RT_USING_ADC is not set +# CONFIG_RT_USING_DAC is not set +# CONFIG_RT_USING_PWM is not set +# CONFIG_RT_USING_MTD_NOR is not set +# CONFIG_RT_USING_MTD_NAND is not set +# CONFIG_RT_USING_PM is not set +# CONFIG_RT_USING_RTC is not set +# CONFIG_RT_USING_SDIO is not set +# CONFIG_RT_USING_SPI is not set +# CONFIG_RT_USING_WDT is not set +# CONFIG_RT_USING_AUDIO is not set +# CONFIG_RT_USING_SENSOR is not set +# CONFIG_RT_USING_TOUCH is not set +# CONFIG_RT_USING_HWCRYPTO is not set +# CONFIG_RT_USING_PULSE_ENCODER is not set +# CONFIG_RT_USING_INPUT_CAPTURE is not set +# CONFIG_RT_USING_WIFI is not set + +# +# Using USB +# +# CONFIG_RT_USING_USB_HOST is not set +# CONFIG_RT_USING_USB_DEVICE is not set + +# +# POSIX layer and C standard library +# +CONFIG_RT_USING_LIBC=y +CONFIG_RT_USING_PTHREADS=y +CONFIG_PTHREAD_NUM_MAX=8 +CONFIG_RT_USING_POSIX=y +# CONFIG_RT_USING_POSIX_MMAP is not set +# CONFIG_RT_USING_POSIX_TERMIOS is not set +# CONFIG_RT_USING_POSIX_GETLINE is not set +# CONFIG_RT_USING_POSIX_AIO is not set +CONFIG_RT_LIBC_USING_TIME=y +# CONFIG_RT_USING_MODULE is not set +CONFIG_RT_LIBC_DEFAULT_TIMEZONE=8 + +# +# Network +# + +# +# Socket abstraction layer +# +# CONFIG_RT_USING_SAL is not set + +# +# Network interface device +# +# CONFIG_RT_USING_NETDEV is not set + +# +# light weight TCP/IP stack +# +# CONFIG_RT_USING_LWIP is not set + +# +# AT commands +# +# CONFIG_RT_USING_AT is not set + +# +# VBUS(Virtual Software BUS) +# +# CONFIG_RT_USING_VBUS is not set + +# +# Utilities +# +# CONFIG_RT_USING_RYM is not set +# CONFIG_RT_USING_ULOG is not set +# CONFIG_RT_USING_UTEST is not set +# CONFIG_RT_USING_VAR_EXPORT is not set +# CONFIG_RT_USING_RT_LINK is not set + +# +# RT-Thread Utestcases +# +# CONFIG_RT_USING_UTESTCASES is not set + +# +# Hardware Drivers Config +# +CONFIG_SOC_IMXRT1052CVL5B=y + +# +# On-chip Peripheral Drivers +# +CONFIG_BSP_USING_BOOT_IMAGE=y +# CONFIG_BSP_USING_DMA is not set +CONFIG_BSP_USING_GPIO=y +CONFIG_BSP_USING_LPUART=y +CONFIG_BSP_USING_LPUART1=y +# CONFIG_BSP_LPUART1_RX_USING_DMA is not set +# CONFIG_BSP_LPUART1_TX_USING_DMA is not set +# CONFIG_BSP_USING_LPUART2 is not set +# CONFIG_BSP_USING_LPUART3 is not set +# CONFIG_BSP_USING_LPUART4 is not set +# CONFIG_BSP_USING_LPUART8 is not set +# CONFIG_BSP_USING_I2C is not set +# CONFIG_BSP_USING_CAN is not set +# CONFIG_BSP_USING_RTC is not set + +# +# Onboard Peripheral Drivers +# +CONFIG_BSP_USING_SDRAM=y + +# +# MicroPython +# +# CONFIG_PKG_USING_MICROPYTHON is not set + +# +# More Drivers +# +# CONFIG_PKG_USING_RW007 is not set +# CONFIG_DRV_USING_OV2640 is not set + +# +# APP_Framework +# + +# +# Framework +# +CONFIG_TRANSFORM_LAYER_ATTRIUBUTE=y +# CONFIG_ADD_XIZI_FETURES is not set +# CONFIG_ADD_NUTTX_FETURES is not set +CONFIG_ADD_RTTHREAD_FETURES=y +# CONFIG_SUPPORT_SENSOR_FRAMEWORK is not set +# CONFIG_SUPPORT_CONNECTION_FRAMEWORK is not set +# CONFIG_SUPPORT_KNOWING_FRAMEWORK is not set +# CONFIG_SUPPORT_CONTROL_FRAMEWORK is not set + +# +# Security +# +# CONFIG_CRYPTO is not set + +# +# Applications +# + +# +# config stack size and priority of main task +# +CONFIG_MAIN_KTASK_STACK_SIZE=1024 + +# +# ota app +# +# CONFIG_APPLICATION_OTA is not set + +# +# test app +# +# CONFIG_USER_TEST is not set + +# +# connection app +# +# CONFIG_APPLICATION_CONNECTION is not set + +# +# control app +# + +# +# knowing app +# +# CONFIG_APPLICATION_KNOWING is not set + +# +# sensor app +# +# CONFIG_APPLICATION_SENSOR is not set +# CONFIG_USING_EMBEDDED_DATABASE_APP is not set + +# +# lib +# +CONFIG_APP_SELECT_NEWLIB=y +# CONFIG_APP_SELECT_OTHER_LIB is not set +# CONFIG_LIB_USING_CJSON is not set +# CONFIG_LIB_USING_QUEUE is not set +# CONFIG_LIB_LV is not set +# CONFIG_USING_EMBEDDED_DATABASE is not set diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/Kconfig b/Ubiquitous/RT_Thread/aiit_board/xidatong/Kconfig new file mode 100644 index 000000000..478f8394b --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/Kconfig @@ -0,0 +1,29 @@ +mainmenu "RT-Thread Configuration" + +config ROOT_DIR + string + default "../../../.." + +config BSP_DIR + string + default "." + +config RT_Thread_DIR + string + default "../.." + +config RTT_DIR + string + default "../../rt-thread" + +config APP_DIR + string + default "../../../../APP_Framework" + +source "$RTT_DIR/Kconfig" +source "$RTT_DIR/bsp/imxrt/libraries/Kconfig" +source "board/Kconfig" +source "$RT_Thread_DIR/micropython/Kconfig" +source "$RT_Thread_DIR/app_match_rt-thread/Kconfig" +source "$ROOT_DIR/APP_Framework/Kconfig" + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/README.md b/Ubiquitous/RT_Thread/aiit_board/xidatong/README.md new file mode 100644 index 000000000..a29a927cb --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/README.md @@ -0,0 +1,121 @@ +# XiDaTong_ARM_Reference_Resource + +## 1. 矽达通介绍 + +矽达通外观图: + +![](https://s2.loli.net/2022/03/17/56PYhSplI1Ud89a.png) + +拆开后盖: + +![](https://s2.loli.net/2022/03/17/5SkJish7VqRfwrX.png) + +矽达通烧录这里介绍两种方式,分别是 NXP-MCUBootUtility 和 Keil MDK5 + +## 2. NXP-MCUBootUtility 方式烧录 + +**[NXP-MCUBootUtility](https://github.com/JayHeng/NXP-MCUBootUtility/tree/v3.4.0)** 是一款开源免费的专为 NXP MCU 安全启动而设计的 GUI 工具。目前主要支持 i.MXRT、LPC、Kinetis 系列 MCU 芯片 + +> ### 测试环境 + +- Windows + +- NXP-MCUBootUtility v3.4.0 + +> ### 烧录流程 + +将矽达通串口1通过 usb 转串口连接至电脑,并在电脑端查看到相应端口,如下图,com15 + +![](https://s2.loli.net/2022/03/17/b2alJPrmvcEXh5Z.png)![](https://s2.loli.net/2022/03/17/lu2jfeGnyzHKZpD.png) + +打开 NXP-MCUBootUtility.exe + +确保一下配置选项正确,COM Port记得选择上述对应的串口 + +![](https://s2.loli.net/2022/03/16/3z2NLbqlS4f6VGY.png) + +将拨码开关拨到 1 on 2 on 3 off 4 off 进入 Serial Download Programming(SDP) 模式, 重新连接电源 + +先点击 Connect to ROM,若连接成功按钮会变蓝 + +![](https://s2.loli.net/2022/03/16/9pefoEvilVYSOrh.png) + +在 Application Image File 一栏中选择要烧录的 elf 文件,文件格式选择 .out(elf) from GCC ARM,然后点击 All-In-One Action 烧录即可 + +![](https://s2.loli.net/2022/03/16/SrEywuekORU2sNz.png) + +烧录完后后,将拨码开关拨回 1 off 2 off 3 off 4 off 进入 nor-flash 启动模式,重新上电,即可从 QSPI Flash 启动程序,此时可以从串口看到调试信息 + +`注:由于采用串口烧录,在连接和烧录的时候记得先关闭串口调试工具` + +## 2. Keil MDK 方式烧录 + +Keil MDK 是一系列基于 Arm Cortex-M 的微控制器设备的完整软件开发环境,可以自行去官网 **[购买下载](https://www.keil.com/download/product/)** ,需要注意的是请选择使用 Keil MDK5.24a 及以上版本 + +开发板连接 CMSIS-DAP 调试器,如下图所示,连接 DIO/CLK/GND 对应的三个引脚即可 + +![](https://s2.loli.net/2022/03/17/V6sQ8R5SXHMbZdU.png) + +> ### 芯片支持包导入 + +去keil官网 [http://www.keil.com/dd2/pack/#/eula-container](http://www.keil.com/dd2/pack/#/eula-container) 下载对应的板级安装包 + +![](https://s2.loli.net/2022/03/17/Fofnw1ajkuyOLmi.png) + +注意: 安装包可能随时间推移,版本有所改动,可选择最新版本下载。 + +下载完成,安装即可。 + +> ### 烧写固件安装 + +将开发板烧写固件复制到 Keil5 安装目录 Keil_v5\ARM\Flash\MIMXRT_QSPIFLASH.FLM,该固件可以兼容32M以下nor Flash烧写。 + +例如: c:\Keil_v5\ARM\Flash\MIMXRT_QSPIFLASH.FLM + +> ### Keil 环境配置 + +查看仿真器是否连接成功: + +![](https://s2.loli.net/2022/03/17/xmQqBslFL1j2SDN.png) + +![](https://s2.loli.net/2022/03/17/H5it68ZWzuRwA4J.png) + +> ### 添加烧写固件 + +选择 Flash Download,删除原来的烧写配置 + +![](https://s2.loli.net/2022/03/17/xOZCnXdaErIF5oS.png) + +添加该烧写固件,size 大小为 32MB + +![](https://s2.loli.net/2022/03/17/xfCIsgOF2N5t3pM.png) + +下载的一些设置记得勾上: + +![](https://s2.loli.net/2022/03/17/acizCh5tH7MJATO.png)![](https://s2.loli.net/2022/03/17/cUqhyRgoPFQHW6L.png) + +然后编译烧录即可,keil下载不需要进入 SDP 模式,无需拨拨码开关。 + + + +## 3.矽达通硬件资源 + +| 端口 | 功能 | +| :------------: | :----------------: | +| uart1 | shell | +| uart3 | 485CH1(外围接口) | +| uart4 | 485CH2(外围接口) | +| uart8 | ec200t 4G 通讯 | +| uart2 | wifi esp07 | +| ch438 EXTU2 | Bluetooth HC08 | +| ch438 EXTU3 | Lora E220-400T22S | +| ch438 EXTU1 | zigbee E18-MS1PA1 | +| SD | sd卡 | +| usb1 | ec200t 4G通讯 | +| usb2 | 外围usb接口 | +| can | can外围接口 | +| IIC | 屏幕 | +| 其他CH438 EXTU | 外围接口 | + + + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/SConscript b/Ubiquitous/RT_Thread/aiit_board/xidatong/SConscript new file mode 100644 index 000000000..c7ef7659e --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/SConscript @@ -0,0 +1,14 @@ +# for module compiling +import os +from building import * + +cwd = GetCurrentDir() +objs = [] +list = os.listdir(cwd) + +for d in list: + path = os.path.join(cwd, d) + if os.path.isfile(os.path.join(path, 'SConscript')): + objs = objs + SConscript(os.path.join(d, 'SConscript')) + +Return('objs') diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/SConstruct b/Ubiquitous/RT_Thread/aiit_board/xidatong/SConstruct new file mode 100644 index 000000000..525661e52 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/SConstruct @@ -0,0 +1,85 @@ +import os +import sys +import rtconfig + +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') +else: + RTT_ROOT = os.path.normpath(os.getcwd() + '/../../rt-thread') + +sys.path = sys.path + [os.path.join(RTT_ROOT, 'tools')] +try: + from building import * +except: + print('Cannot found RT-Thread root directory, please check RTT_ROOT') + print(RTT_ROOT) + exit(-1) + +TARGET = 'rtthread.' + rtconfig.TARGET_EXT +DefaultEnvironment(tools=[]) +if rtconfig.PLATFORM == 'armcc': + env = Environment(tools = ['mingw'], + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', + LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, + # overwrite cflags, because cflags has '--C99' + CXXCOM = '$CXX -o $TARGET --cpp -c $CXXFLAGS $_CCCOMCOM $SOURCES') +else: + env = Environment(tools = ['mingw'], + AS = rtconfig.AS, ASFLAGS = rtconfig.AFLAGS, + CC = rtconfig.CC, CFLAGS = rtconfig.CFLAGS, + CXX = rtconfig.CXX, CXXFLAGS = rtconfig.CXXFLAGS, + AR = rtconfig.AR, ARFLAGS = '-rc', + LINK = rtconfig.LINK, LINKFLAGS = rtconfig.LFLAGS, + CXXCOM = '$CXX -o $TARGET -c $CXXFLAGS $_CCCOMCOM $SOURCES') + +env.PrependENVPath('PATH', rtconfig.EXEC_PATH) + +if rtconfig.PLATFORM == 'iar': + env.Replace(CCCOM = ['$CC $CFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -o $TARGET $SOURCES']) + env.Replace(ARFLAGS = ['']) + env.Replace(LINKCOM = env["LINKCOM"] + ' --map rtthread.map') + +Export('RTT_ROOT') +Export('rtconfig') + +SDK_ROOT = os.path.abspath('./') + +#if os.path.exists(SDK_ROOT + '/libraries'): +# libraries_path_prefix = SDK_ROOT + '/libraries' +#else: +# libraries_path_prefix = os.path.dirname(SDK_ROOT) + '/libraries' +libraries_path_prefix = RTT_ROOT + '/bsp/imxrt/libraries' +SDK_LIB = libraries_path_prefix +Export('SDK_LIB') + +# prepare building environment +objs = PrepareBuilding(env, RTT_ROOT, has_libcpu=False) + +imxrt_library = 'MIMXRT1050' +rtconfig.BSP_LIBRARY_TYPE = imxrt_library + +# include libraries +objs.extend(SConscript(os.path.join(libraries_path_prefix, imxrt_library, 'SConscript'))) + +# include drivers +objs.extend(SConscript(os.path.join(libraries_path_prefix, 'drivers', 'SConscript'))) + +# include more drivers +objs.extend(SConscript(os.getcwd() + '/../../app_match_rt-thread/SConscript')) + +# include APP_Framework/Framework +objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/Framework/SConscript')) + +# include APP_Framework/Applications +objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/Applications/SConscript')) + +# include APP_Framework/lib +objs.extend(SConscript(os.getcwd() + '/../../../../APP_Framework/lib/SConscript')) + +# include Ubiquitous/RT-Thread/micropython +objs.extend(SConscript(os.getcwd() + '/../../micropython/SConscript')) +# make a building +DoBuilding(TARGET, objs) diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/applications/SConscript b/Ubiquitous/RT_Thread/aiit_board/xidatong/applications/SConscript new file mode 100644 index 000000000..20bf17933 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/applications/SConscript @@ -0,0 +1,17 @@ +import os +import rtconfig +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +# add for startup script +if rtconfig.CROSS_TOOL == 'gcc': + CPPDEFINES = ['__START=entry'] +else: + CPPDEFINES = [] + +group = DefineGroup('Applications', src, depend = [''], CPPPATH = CPPPATH, CPPDEFINES=CPPDEFINES) + +Return('group') diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/applications/main.c b/Ubiquitous/RT_Thread/aiit_board/xidatong/applications/main.c new file mode 100644 index 000000000..314b7f590 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/applications/main.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2019-04-29 tyustli first version + * + */ + +#include +#include +#include "drv_gpio.h" +#include + +/* defined the LED pin: GPIO1_IO9 */ +#define LED0_PIN GET_PIN(1,9) + +int main(void) +{ + /* set LED0 pin mode to output */ + rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); + rt_kprintf("XIUOS xidatong build %s %s\n",__DATE__,__TIME__); + while (1) + { + rt_pin_write(LED0_PIN, PIN_HIGH); + rt_thread_mdelay(500); + rt_pin_write(LED0_PIN, PIN_LOW); + rt_thread_mdelay(500); + } +} + +#ifdef BSP_USING_SDRAM +static void sram_test2(void) +{ + char *p =NULL; + p = rt_malloc(1024*1024*8); + if(p == NULL) + { + rt_kprintf("apply for 8MB memory fail ~!!!"); + } + else + { + rt_kprintf("appyle for 8MB memory success!!!"); + } + rt_free(p); +} +MSH_CMD_EXPORT(sram_test2, sram test2); +#endif diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/Kconfig b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/Kconfig new file mode 100644 index 000000000..3c2355e2b --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/Kconfig @@ -0,0 +1,216 @@ +menu "Hardware Drivers Config" + +config SOC_IMXRT1052CVL5B + bool + select SOC_MIMXRT1050_SERIES + select RT_USING_COMPONENTS_INIT + select RT_USING_USER_MAIN + default y + +menu "On-chip Peripheral Drivers" + + config BSP_USING_BOOT_IMAGE + bool "Enable boot image" + default y + config BSP_USING_DMA + bool "Enable DMA" + default n + + config BSP_USING_GPIO + bool "Enable GPIO" + select RT_USING_PIN + default y + menuconfig BSP_USING_LPUART + bool "Enable UART" + select RT_USING_SERIAL + default y + + if BSP_USING_LPUART + config BSP_USING_LPUART1 + bool "Enable LPUART1" + default y + + config BSP_LPUART1_RX_USING_DMA + bool "Enable LPUART1 RX DMA" + depends on BSP_USING_LPUART1 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART1_RX_DMA_CHANNEL + depends on BSP_LPUART1_RX_USING_DMA + int "Set LPUART1 RX DMA channel (0-32)" + default 0 + + config BSP_LPUART1_TX_USING_DMA + bool "Enable LPUART1 TX DMA" + depends on BSP_USING_LPUART1 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART1_TX_DMA_CHANNEL + depends on BSP_LPUART1_TX_USING_DMA + int "Set LPUART1 TX DMA channel (0-32)" + default 1 + + config BSP_USING_LPUART2 + bool "Enable LPUART2" + default y + + config BSP_LPUART2_RX_USING_DMA + bool "Enable LPUART2 RX DMA" + depends on BSP_USING_LPUART2 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART2_RX_DMA_CHANNEL + depends on BSP_LPUART2_RX_USING_DMA + int "Set LPUART2 RX DMA channel (0-32)" + default 2 + + config BSP_LPUART2_TX_USING_DMA + bool "Enable LPUART2 TX DMA" + depends on BSP_USING_LPUART2 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART2_TX_DMA_CHANNEL + depends on BSP_LPUART2_TX_USING_DMA + int "Set LPUART2 TX DMA channel (0-32)" + default 3 + + config BSP_USING_LPUART3 + bool "Enable LPUART3" + default y + + config BSP_LPUART3_RX_USING_DMA + bool "Enable LPUART3 RX DMA" + depends on BSP_USING_LPUART3 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART3_RX_DMA_CHANNEL + depends on BSP_LPUART3_RX_USING_DMA + int "Set LPUART3 RX DMA channel (0-32)" + default 4 + + config BSP_LPUART3_TX_USING_DMA + bool "Enable LPUART3 TX DMA" + depends on BSP_USING_LPUART3 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART3_TX_DMA_CHANNEL + depends on BSP_LPUART3_TX_USING_DMA + int "Set LPUART3 TX DMA channel (0-32)" + default 5 + + config BSP_USING_LPUART4 + bool "Enable LPUART4" + default n + + config BSP_LPUART4_RX_USING_DMA + bool "Enable LPUART4 RX DMA" + depends on BSP_USING_LPUART4 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART4_RX_DMA_CHANNEL + depends on BSP_LPUART4_RX_USING_DMA + int "Set LPUART4 RX DMA channel (0-32)" + default 6 + + config BSP_LPUART4_TX_USING_DMA + bool "Enable LPUART4 TX DMA" + depends on BSP_USING_LPUART4 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART4_TX_DMA_CHANNEL + depends on BSP_LPUART4_TX_USING_DMA + int "Set LPUART4 TX DMA channel (0-32)" + default 7 + + + config BSP_USING_LPUART8 + bool "Enable LPUART8" + default y + + config BSP_LPUART8_RX_USING_DMA + bool "Enable LPUART8 RX DMA" + depends on BSP_USING_LPUART8 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART8_RX_DMA_CHANNEL + depends on BSP_LPUART8_RX_USING_DMA + int "Set LPUART8 RX DMA channel (0-32)" + default 8 + + config BSP_LPUART8_TX_USING_DMA + bool "Enable LPUART8 TX DMA" + depends on BSP_USING_LPUART8 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n + + config BSP_LPUART8_TX_DMA_CHANNEL + depends on BSP_LPUART8_TX_USING_DMA + int "Set LPUART8 TX DMA channel (0-32)" + default 9 + + endif + menuconfig BSP_USING_I2C + bool "Enable I2C" + select RT_USING_I2C + default n + if BSP_USING_I2C + config BSP_USING_I2C1 + bool "Enable I2C1" + default n + choice + prompt "Select I2C1 badurate" + default HW_I2C1_BADURATE_100kHZ + + config HW_I2C1_BADURATE_100kHZ + bool "Badurate 100kHZ" + + config HW_I2C1_BADURATE_400kHZ + bool "Badurate 400kHZ" + endchoice + endif + + menuconfig BSP_USING_CAN + bool "Enable CAN" + select RT_USING_CAN + default n + + if BSP_USING_CAN + config BSP_USING_CAN1 + bool "Enable CAN1" + default y + endif + + config BSP_USING_RTC + bool "Enable RTC" + select RT_USING_RTC + default n + +endmenu + +menu "Onboard Peripheral Drivers" + config BSP_USING_SDRAM + bool "Enable SDRAM" + default n +endmenu + + +endmenu diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/MCUX_Config.mex b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/MCUX_Config.mex new file mode 100644 index 000000000..5b8653181 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/MCUX_Config.mex @@ -0,0 +1,468 @@ + + + + MIMXRT1052xxxxB + MIMXRT1052DVL6B + IMXRT1050-EVKB + A + ksdk2_0 + + + + + + + false + false + + + + + 5.0.2 + + + + + + + + + + + Configures pin routing and optionally pin electrical features. + + false + core0 + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5.0.2 + + + + + + + + + true + + + + + INPUT + + + + + true + + + + + OUTPUT + + + + + true + + + + + INPUT + + + + + true + + + + + OUTPUT + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + true + + + + + 2.2.4 + + + + + true + + + + + 2.1.5 + + + + + 5.0.2 + + + + + + + + + 0 + + + + + true + + + + + true + + + + + 0 + + + + + true + + + + + true + + + + + 0 + + + + + true + + + + + true + + + + + 0 + + + + + true + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.c b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.c new file mode 100644 index 000000000..2df780010 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.c @@ -0,0 +1,465 @@ +/* + * How to setup clock using clock driver functions: + * + * 1. Call CLOCK_InitXXXPLL() to configure corresponding PLL clock. + * + * 2. Call CLOCK_InitXXXpfd() to configure corresponding PLL pfd clock. + * + * 3. Call CLOCK_SetMux() to configure corresponding clock source for target clock out. + * + * 4. Call CLOCK_SetDiv() to configure corresponding clock divider for target clock out. + * + * 5. Call CLOCK_SetXtalFreq() to set XTAL frequency based on board settings. + * + */ + +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!GlobalInfo +product: Clocks v5.0 +processor: MIMXRT1052xxxxB +package_id: MIMXRT1052DVL6B +mcu_data: ksdk2_0 +processor_version: 5.0.2 +board: IMXRT1050-EVKB + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ + +#include "clock_config.h" +#include "fsl_iomuxc.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Variables + ******************************************************************************/ +/* System clock frequency. */ +extern uint32_t SystemCoreClock; + +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ +void BOARD_InitBootClocks(void) +{ + BOARD_BootClockRUN(); +} + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/* TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!Configuration +name: BOARD_BootClockRUN +called_from_default_init: true +outputs: +- {id: AHB_CLK_ROOT.outFreq, value: 600 MHz} +- {id: CAN_CLK_ROOT.outFreq, value: 20 MHz} +- {id: CKIL_SYNC_CLK_ROOT.outFreq, value: 32.768 kHz} +- {id: CLK_1M.outFreq, value: 1 MHz} +- {id: CLK_24M.outFreq, value: 24 MHz} +- {id: CSI_CLK_ROOT.outFreq, value: 12 MHz} +- {id: ENET1_TX_CLK.outFreq, value: 2.4 MHz} +- {id: ENET_125M_CLK.outFreq, value: 2.4 MHz} +- {id: ENET_25M_REF_CLK.outFreq, value: 1.2 MHz} +- {id: FLEXIO1_CLK_ROOT.outFreq, value: 30 MHz} +- {id: FLEXIO2_CLK_ROOT.outFreq, value: 30 MHz} +- {id: FLEXSPI_CLK_ROOT.outFreq, value: 2880/11 MHz} +- {id: GPT1_ipg_clk_highfreq.outFreq, value: 75 MHz} +- {id: GPT2_ipg_clk_highfreq.outFreq, value: 75 MHz} +- {id: IPG_CLK_ROOT.outFreq, value: 150 MHz} +- {id: LCDIF_CLK_ROOT.outFreq, value: 67.5/7 MHz} +- {id: LPI2C_CLK_ROOT.outFreq, value: 60 MHz} +- {id: LPSPI_CLK_ROOT.outFreq, value: 105.6 MHz} +- {id: LVDS1_CLK.outFreq, value: 1.2 GHz} +- {id: MQS_MCLK.outFreq, value: 1080/17 MHz} +- {id: PERCLK_CLK_ROOT.outFreq, value: 75 MHz} +- {id: PLL7_MAIN_CLK.outFreq, value: 24 MHz} +- {id: SAI1_CLK_ROOT.outFreq, value: 1080/17 MHz} +- {id: SAI1_MCLK1.outFreq, value: 1080/17 MHz} +- {id: SAI1_MCLK2.outFreq, value: 1080/17 MHz} +- {id: SAI1_MCLK3.outFreq, value: 30 MHz} +- {id: SAI2_CLK_ROOT.outFreq, value: 1080/17 MHz} +- {id: SAI2_MCLK1.outFreq, value: 1080/17 MHz} +- {id: SAI2_MCLK3.outFreq, value: 30 MHz} +- {id: SAI3_CLK_ROOT.outFreq, value: 1080/17 MHz} +- {id: SAI3_MCLK1.outFreq, value: 1080/17 MHz} +- {id: SAI3_MCLK3.outFreq, value: 30 MHz} +- {id: SEMC_CLK_ROOT.outFreq, value: 75 MHz} +- {id: SPDIF0_CLK_ROOT.outFreq, value: 30 MHz} +- {id: TRACE_CLK_ROOT.outFreq, value: 352/3 MHz} +- {id: UART_CLK_ROOT.outFreq, value: 80 MHz} +- {id: USDHC1_CLK_ROOT.outFreq, value: 198 MHz} +- {id: USDHC2_CLK_ROOT.outFreq, value: 198 MHz} +settings: +- {id: CCM.AHB_PODF.scale, value: '1', locked: true} +- {id: CCM.ARM_PODF.scale, value: '2', locked: true} +- {id: CCM.CAN_CLK_PODF.scale, value: '4', locked: true} +- {id: CCM.FLEXSPI_PODF.scale, value: '1', locked: true} +- {id: CCM.FLEXSPI_SEL.sel, value: CCM_ANALOG.PLL3_PFD0_CLK} +- {id: CCM.LCDIF_PODF.scale, value: '8', locked: true} +- {id: CCM.LCDIF_PRED.scale, value: '7', locked: true} +- {id: CCM.LPSPI_PODF.scale, value: '5', locked: true} +- {id: CCM.PERCLK_PODF.scale, value: '2', locked: true} +- {id: CCM.SEMC_PODF.scale, value: '8'} +- {id: CCM.TRACE_PODF.scale, value: '3', locked: true} +- {id: CCM_ANALOG.PLL1_BYPASS.sel, value: CCM_ANALOG.PLL1} +- {id: CCM_ANALOG.PLL1_PREDIV.scale, value: '1', locked: true} +- {id: CCM_ANALOG.PLL1_VDIV.scale, value: '50', locked: true} +- {id: CCM_ANALOG.PLL2.denom, value: '1', locked: true} +- {id: CCM_ANALOG.PLL2.num, value: '0', locked: true} +- {id: CCM_ANALOG.PLL2_BYPASS.sel, value: CCM_ANALOG.PLL2_OUT_CLK} +- {id: CCM_ANALOG.PLL2_PFD0_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD0} +- {id: CCM_ANALOG.PLL2_PFD1_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD1} +- {id: CCM_ANALOG.PLL2_PFD2_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD2} +- {id: CCM_ANALOG.PLL2_PFD3_BYPASS.sel, value: CCM_ANALOG.PLL2_PFD3} +- {id: CCM_ANALOG.PLL3_BYPASS.sel, value: CCM_ANALOG.PLL3} +- {id: CCM_ANALOG.PLL3_PFD0_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD0} +- {id: CCM_ANALOG.PLL3_PFD0_DIV.scale, value: '33', locked: true} +- {id: CCM_ANALOG.PLL3_PFD0_MUL.scale, value: '18', locked: true} +- {id: CCM_ANALOG.PLL3_PFD1_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD1} +- {id: CCM_ANALOG.PLL3_PFD2_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD2} +- {id: CCM_ANALOG.PLL3_PFD3_BYPASS.sel, value: CCM_ANALOG.PLL3_PFD3} +- {id: CCM_ANALOG.PLL4.denom, value: '50'} +- {id: CCM_ANALOG.PLL4.div, value: '47'} +- {id: CCM_ANALOG.PLL5.denom, value: '1'} +- {id: CCM_ANALOG.PLL5.div, value: '40'} +- {id: CCM_ANALOG.PLL5.num, value: '0'} +- {id: CCM_ANALOG_PLL_ENET_POWERDOWN_CFG, value: 'Yes'} +- {id: CCM_ANALOG_PLL_USB1_POWER_CFG, value: 'Yes'} +sources: +- {id: XTALOSC24M.OSC.outFreq, value: 24 MHz, enabled: true} +- {id: XTALOSC24M.RTC_OSC.outFreq, value: 32.768 kHz, enabled: true} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/ + +/******************************************************************************* + * Variables for BOARD_BootClockRUN configuration + ******************************************************************************/ +const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN = + { + .loopDivider = 100, /* PLL loop divider, Fout = Fin * 50 */ + .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */ + }; +const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN = + { + .loopDivider = 1, /* PLL loop divider, Fout = Fin * ( 20 + loopDivider*2 + numerator / denominator ) */ + .numerator = 0, /* 30 bit numerator of fractional loop divider */ + .denominator = 1, /* 30 bit denominator of fractional loop divider */ + .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */ + }; +const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN = + { + .loopDivider = 0, /* PLL loop divider, Fout = Fin * 20 */ + .src = 0, /* Bypass clock source, 0 - OSC 24M, 1 - CLK1_P and CLK1_N */ + }; +/******************************************************************************* + * Code for BOARD_BootClockRUN configuration + ******************************************************************************/ +void BOARD_BootClockRUN(void) +{ + /* Init RTC OSC clock frequency. */ + CLOCK_SetRtcXtalFreq(32768U); + /* Enable 1MHz clock output. */ + XTALOSC24M->OSC_CONFIG2 |= XTALOSC24M_OSC_CONFIG2_ENABLE_1M_MASK; + /* Use free 1MHz clock output. */ + XTALOSC24M->OSC_CONFIG2 &= ~XTALOSC24M_OSC_CONFIG2_MUX_1M_MASK; + /* Set XTAL 24MHz clock frequency. */ + CLOCK_SetXtalFreq(24000000U); + /* Enable XTAL 24MHz clock source. */ + CLOCK_InitExternalClk(0); + /* Enable internal RC. */ + CLOCK_InitRcOsc24M(); + /* Switch clock source to external OSC. */ + CLOCK_SwitchOsc(kCLOCK_XtalOsc); + /* Set Oscillator ready counter value. */ + CCM->CCR = (CCM->CCR & (~CCM_CCR_OSCNT_MASK)) | CCM_CCR_OSCNT(127); + /* Setting PeriphClk2Mux and PeriphMux to provide stable clock before PLLs are initialed */ + CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 1); /* Set PERIPH_CLK2 MUX to OSC */ + CLOCK_SetMux(kCLOCK_PeriphMux, 1); /* Set PERIPH_CLK MUX to PERIPH_CLK2 */ + /* Setting the VDD_SOC to 1.275V. It is necessary to config AHB to 600Mhz. */ + DCDC->REG3 = (DCDC->REG3 & (~DCDC_REG3_TRG_MASK)) | DCDC_REG3_TRG(0x13); + /* Waiting for DCDC_STS_DC_OK bit is asserted */ + while (DCDC_REG0_STS_DC_OK_MASK != (DCDC_REG0_STS_DC_OK_MASK & DCDC->REG0)) + { + } + /* Set AHB_PODF. */ + CLOCK_SetDiv(kCLOCK_AhbDiv, 0); + /* Disable IPG clock gate. */ + CLOCK_DisableClock(kCLOCK_Adc1); + CLOCK_DisableClock(kCLOCK_Adc2); + CLOCK_DisableClock(kCLOCK_Xbar1); + CLOCK_DisableClock(kCLOCK_Xbar2); + CLOCK_DisableClock(kCLOCK_Xbar3); + /* Set IPG_PODF. */ + CLOCK_SetDiv(kCLOCK_IpgDiv, 3); + /* Set ARM_PODF. */ + CLOCK_SetDiv(kCLOCK_ArmDiv, 1); + /* Set PERIPH_CLK2_PODF. */ + CLOCK_SetDiv(kCLOCK_PeriphClk2Div, 0); + /* Disable PERCLK clock gate. */ + CLOCK_DisableClock(kCLOCK_Gpt1); + CLOCK_DisableClock(kCLOCK_Gpt1S); + CLOCK_DisableClock(kCLOCK_Gpt2); + CLOCK_DisableClock(kCLOCK_Gpt2S); + CLOCK_DisableClock(kCLOCK_Pit); + /* Set PERCLK_PODF. */ + CLOCK_SetDiv(kCLOCK_PerclkDiv, 1); + /* Disable USDHC1 clock gate. */ + CLOCK_DisableClock(kCLOCK_Usdhc1); + /* Set USDHC1_PODF. */ + CLOCK_SetDiv(kCLOCK_Usdhc1Div, 1); + /* Set Usdhc1 clock source. */ + CLOCK_SetMux(kCLOCK_Usdhc1Mux, 0); + /* Disable USDHC2 clock gate. */ + CLOCK_DisableClock(kCLOCK_Usdhc2); + /* Set USDHC2_PODF. */ + CLOCK_SetDiv(kCLOCK_Usdhc2Div, 1); + /* Set Usdhc2 clock source. */ + CLOCK_SetMux(kCLOCK_Usdhc2Mux, 0); + /* In SDK projects, SDRAM (configured by SEMC) will be initialized in either debug script or dcd. + * With this macro SKIP_SYSCLK_INIT, system pll (selected to be SEMC source clock in SDK projects) will be left unchanged. + * Note: If another clock source is selected for SEMC, user may want to avoid changing that clock as well.*/ +#ifndef SKIP_SYSCLK_INIT + /* Disable Semc clock gate. */ + CLOCK_DisableClock(kCLOCK_Semc); + /* Set SEMC_PODF. */ + CLOCK_SetDiv(kCLOCK_SemcDiv, 7); + /* Set Semc alt clock source. */ + CLOCK_SetMux(kCLOCK_SemcAltMux, 0); + /* Set Semc clock source. */ + CLOCK_SetMux(kCLOCK_SemcMux, 0); +#endif + /* In SDK projects, external flash (configured by FLEXSPI) will be initialized by dcd. + * With this macro XIP_EXTERNAL_FLASH, usb1 pll (selected to be FLEXSPI clock source in SDK projects) will be left unchanged. + * Note: If another clock source is selected for FLEXSPI, user may want to avoid changing that clock as well.*/ +#if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)) + /* Disable Flexspi clock gate. */ + CLOCK_DisableClock(kCLOCK_FlexSpi); + /* Set FLEXSPI_PODF. */ + CLOCK_SetDiv(kCLOCK_FlexspiDiv, 0); + /* Set Flexspi clock source. */ + CLOCK_SetMux(kCLOCK_FlexspiMux, 3); +#endif + /* Disable CSI clock gate. */ + CLOCK_DisableClock(kCLOCK_Csi); + /* Set CSI_PODF. */ + CLOCK_SetDiv(kCLOCK_CsiDiv, 1); + /* Set Csi clock source. */ + CLOCK_SetMux(kCLOCK_CsiMux, 0); + /* Disable LPSPI clock gate. */ + CLOCK_DisableClock(kCLOCK_Lpspi1); + CLOCK_DisableClock(kCLOCK_Lpspi2); + CLOCK_DisableClock(kCLOCK_Lpspi3); + CLOCK_DisableClock(kCLOCK_Lpspi4); + /* Set LPSPI_PODF. */ + CLOCK_SetDiv(kCLOCK_LpspiDiv, 4); + /* Set Lpspi clock source. */ + CLOCK_SetMux(kCLOCK_LpspiMux, 2); + /* Disable TRACE clock gate. */ + CLOCK_DisableClock(kCLOCK_Trace); + /* Set TRACE_PODF. */ + CLOCK_SetDiv(kCLOCK_TraceDiv, 2); + /* Set Trace clock source. */ + CLOCK_SetMux(kCLOCK_TraceMux, 2); + /* Disable SAI1 clock gate. */ + CLOCK_DisableClock(kCLOCK_Sai1); + /* Set SAI1_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Sai1PreDiv, 3); + /* Set SAI1_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Sai1Div, 1); + /* Set Sai1 clock source. */ + CLOCK_SetMux(kCLOCK_Sai1Mux, 0); + /* Disable SAI2 clock gate. */ + CLOCK_DisableClock(kCLOCK_Sai2); + /* Set SAI2_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Sai2PreDiv, 3); + /* Set SAI2_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Sai2Div, 1); + /* Set Sai2 clock source. */ + CLOCK_SetMux(kCLOCK_Sai2Mux, 0); + /* Disable SAI3 clock gate. */ + CLOCK_DisableClock(kCLOCK_Sai3); + /* Set SAI3_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Sai3PreDiv, 3); + /* Set SAI3_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Sai3Div, 1); + /* Set Sai3 clock source. */ + CLOCK_SetMux(kCLOCK_Sai3Mux, 0); + /* Disable Lpi2c clock gate. */ + CLOCK_DisableClock(kCLOCK_Lpi2c1); + CLOCK_DisableClock(kCLOCK_Lpi2c2); + CLOCK_DisableClock(kCLOCK_Lpi2c3); + /* Set LPI2C_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Lpi2cDiv, 0); + /* Set Lpi2c clock source. */ + CLOCK_SetMux(kCLOCK_Lpi2cMux, 0); + /* Disable CAN clock gate. */ + CLOCK_DisableClock(kCLOCK_Can1); + CLOCK_DisableClock(kCLOCK_Can2); + CLOCK_DisableClock(kCLOCK_Can1S); + CLOCK_DisableClock(kCLOCK_Can2S); + /* Set CAN_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_CanDiv, 3); + /* Set Can clock source. */ + CLOCK_SetMux(kCLOCK_CanMux, 2); + /* Disable UART clock gate. */ + CLOCK_DisableClock(kCLOCK_Lpuart1); + CLOCK_DisableClock(kCLOCK_Lpuart2); + CLOCK_DisableClock(kCLOCK_Lpuart3); + CLOCK_DisableClock(kCLOCK_Lpuart4); + CLOCK_DisableClock(kCLOCK_Lpuart5); + CLOCK_DisableClock(kCLOCK_Lpuart6); + CLOCK_DisableClock(kCLOCK_Lpuart7); + CLOCK_DisableClock(kCLOCK_Lpuart8); + /* Set UART_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_UartDiv, 0); + /* Set Uart clock source. */ + CLOCK_SetMux(kCLOCK_UartMux, 0); + /* Disable LCDIF clock gate. */ + CLOCK_DisableClock(kCLOCK_LcdPixel); + /* Set LCDIF_PRED. */ + CLOCK_SetDiv(kCLOCK_LcdifPreDiv, 6); + /* Set LCDIF_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_LcdifDiv, 7); + /* Set Lcdif pre clock source. */ + CLOCK_SetMux(kCLOCK_LcdifPreMux, 5); + /* Disable SPDIF clock gate. */ + CLOCK_DisableClock(kCLOCK_Spdif); + /* Set SPDIF0_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Spdif0PreDiv, 1); + /* Set SPDIF0_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Spdif0Div, 7); + /* Set Spdif clock source. */ + CLOCK_SetMux(kCLOCK_SpdifMux, 3); + /* Disable Flexio1 clock gate. */ + CLOCK_DisableClock(kCLOCK_Flexio1); + /* Set FLEXIO1_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Flexio1PreDiv, 1); + /* Set FLEXIO1_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Flexio1Div, 7); + /* Set Flexio1 clock source. */ + CLOCK_SetMux(kCLOCK_Flexio1Mux, 3); + /* Disable Flexio2 clock gate. */ + CLOCK_DisableClock(kCLOCK_Flexio2); + /* Set FLEXIO2_CLK_PRED. */ + CLOCK_SetDiv(kCLOCK_Flexio2PreDiv, 1); + /* Set FLEXIO2_CLK_PODF. */ + CLOCK_SetDiv(kCLOCK_Flexio2Div, 7); + /* Set Flexio2 clock source. */ + CLOCK_SetMux(kCLOCK_Flexio2Mux, 3); + /* Set Pll3 sw clock source. */ + CLOCK_SetMux(kCLOCK_Pll3SwMux, 0); + /* Init ARM PLL. */ + CLOCK_InitArmPll(&armPllConfig_BOARD_BootClockRUN); + /* In SDK projects, SDRAM (configured by SEMC) will be initialized in either debug script or dcd. + * With this macro SKIP_SYSCLK_INIT, system pll (selected to be SEMC source clock in SDK projects) will be left unchanged. + * Note: If another clock source is selected for SEMC, user may want to avoid changing that clock as well.*/ +#ifndef SKIP_SYSCLK_INIT + /* Init System PLL. */ + CLOCK_InitSysPll(&sysPllConfig_BOARD_BootClockRUN); + /* Init System pfd0. */ + CLOCK_InitSysPfd(kCLOCK_Pfd0, 27); + /* Init System pfd1. */ + CLOCK_InitSysPfd(kCLOCK_Pfd1, 16); + /* Init System pfd2. */ + CLOCK_InitSysPfd(kCLOCK_Pfd2, 24); + /* Init System pfd3. */ + CLOCK_InitSysPfd(kCLOCK_Pfd3, 16); + /* Disable pfd offset. */ + CCM_ANALOG->PLL_SYS &= ~CCM_ANALOG_PLL_SYS_PFD_OFFSET_EN_MASK; +#endif + /* In SDK projects, external flash (configured by FLEXSPI) will be initialized by dcd. + * With this macro XIP_EXTERNAL_FLASH, usb1 pll (selected to be FLEXSPI clock source in SDK projects) will be left unchanged. + * Note: If another clock source is selected for FLEXSPI, user may want to avoid changing that clock as well.*/ +#if !(defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1)) + /* Init Usb1 PLL. */ + CLOCK_InitUsb1Pll(&usb1PllConfig_BOARD_BootClockRUN); + /* Init Usb1 pfd0. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd0, 33); + /* Init Usb1 pfd1. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd1, 16); + /* Init Usb1 pfd2. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, 17); + /* Init Usb1 pfd3. */ + CLOCK_InitUsb1Pfd(kCLOCK_Pfd3, 19); + /* Disable Usb1 PLL output for USBPHY1. */ + CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK; +#endif + /* DeInit Audio PLL. */ + CLOCK_DeinitAudioPll(); + /* Bypass Audio PLL. */ + CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllAudio, 1); + /* Set divider for Audio PLL. */ + CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK; + CCM_ANALOG->MISC2 &= ~CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK; + /* Enable Audio PLL output. */ + CCM_ANALOG->PLL_AUDIO |= CCM_ANALOG_PLL_AUDIO_ENABLE_MASK; + /* DeInit Video PLL. */ + CLOCK_DeinitVideoPll(); + /* Bypass Video PLL. */ + CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_BYPASS_MASK; + /* Set divider for Video PLL. */ + CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & (~CCM_ANALOG_MISC2_VIDEO_DIV_MASK)) | CCM_ANALOG_MISC2_VIDEO_DIV(0); + /* Enable Video PLL output. */ + CCM_ANALOG->PLL_VIDEO |= CCM_ANALOG_PLL_VIDEO_ENABLE_MASK; + /* DeInit Enet PLL. */ + CLOCK_DeinitEnetPll(); + /* Bypass Enet PLL. */ + CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllEnet, 1); + /* Set Enet output divider. */ + CCM_ANALOG->PLL_ENET = (CCM_ANALOG->PLL_ENET & (~CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK)) | CCM_ANALOG_PLL_ENET_DIV_SELECT(1); + /* Enable Enet output. */ + CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_ENABLE_MASK; + /* Enable Enet25M output. */ + CCM_ANALOG->PLL_ENET |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK; + /* DeInit Usb2 PLL. */ + CLOCK_DeinitUsb2Pll(); + /* Bypass Usb2 PLL. */ + CLOCK_SetPllBypass(CCM_ANALOG, kCLOCK_PllUsb2, 1); + /* Enable Usb2 PLL output. */ + CCM_ANALOG->PLL_USB2 |= CCM_ANALOG_PLL_USB2_ENABLE_MASK; + /* Set preperiph clock source. */ + CLOCK_SetMux(kCLOCK_PrePeriphMux, 3); + /* Set periph clock source. */ + CLOCK_SetMux(kCLOCK_PeriphMux, 0); + /* Set periph clock2 clock source. */ + CLOCK_SetMux(kCLOCK_PeriphClk2Mux, 0); + /* Set per clock source. */ + CLOCK_SetMux(kCLOCK_PerclkMux, 0); + /* Set lvds1 clock source. */ + CCM_ANALOG->MISC1 = (CCM_ANALOG->MISC1 & (~CCM_ANALOG_MISC1_LVDS1_CLK_SEL_MASK)) | CCM_ANALOG_MISC1_LVDS1_CLK_SEL(0); + /* Set clock out1 divider. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_DIV_MASK)) | CCM_CCOSR_CLKO1_DIV(0); + /* Set clock out1 source. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO1_SEL_MASK)) | CCM_CCOSR_CLKO1_SEL(1); + /* Set clock out2 divider. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_DIV_MASK)) | CCM_CCOSR_CLKO2_DIV(0); + /* Set clock out2 source. */ + CCM->CCOSR = (CCM->CCOSR & (~CCM_CCOSR_CLKO2_SEL_MASK)) | CCM_CCOSR_CLKO2_SEL(18); + /* Set clock out1 drives clock out1. */ + CCM->CCOSR &= ~CCM_CCOSR_CLK_OUT_SEL_MASK; + /* Disable clock out1. */ + CCM->CCOSR &= ~CCM_CCOSR_CLKO1_EN_MASK; + /* Disable clock out2. */ + CCM->CCOSR &= ~CCM_CCOSR_CLKO2_EN_MASK; + /* Set SAI1 MCLK1 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk1Sel, 0); + /* Set SAI1 MCLK2 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk2Sel, 0); + /* Set SAI1 MCLK3 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI1MClk3Sel, 0); + /* Set SAI2 MCLK3 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI2MClk3Sel, 0); + /* Set SAI3 MCLK3 clock source. */ + IOMUXC_SetSaiMClkClockSource(IOMUXC_GPR, kIOMUXC_GPR_SAI3MClk3Sel, 0); + /* Set MQS configuration. */ + IOMUXC_MQSConfig(IOMUXC_GPR,kIOMUXC_MqsPwmOverSampleRate32, 0); + /* Set ENET Tx clock source. */ + IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1RefClkMode, false); + /* Set GPT1 High frequency reference clock source. */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT1_MASK; + /* Set GPT2 High frequency reference clock source. */ + IOMUXC_GPR->GPR5 &= ~IOMUXC_GPR_GPR5_VREF_1M_CLK_GPT2_MASK; + /* Set SystemCoreClock variable. */ + SystemCoreClock = BOARD_BOOTCLOCKRUN_CORE_CLOCK; +} + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.h new file mode 100644 index 000000000..43fbb9d80 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/clock_config.h @@ -0,0 +1,66 @@ +#ifndef _CLOCK_CONFIG_H_ +#define _CLOCK_CONFIG_H_ + +#include "fsl_common.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#define BOARD_XTAL0_CLK_HZ 24000000U /*!< Board xtal0 frequency in Hz */ + +#define BOARD_XTAL32K_CLK_HZ 32768U /*!< Board xtal32k frequency in Hz */ +/******************************************************************************* + ************************ BOARD_InitBootClocks function ************************ + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes default configuration of clocks. + * + */ +void BOARD_InitBootClocks(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +/******************************************************************************* + ********************** Configuration BOARD_BootClockRUN *********************** + ******************************************************************************/ +/******************************************************************************* + * Definitions for BOARD_BootClockRUN configuration + ******************************************************************************/ +#define BOARD_BOOTCLOCKRUN_CORE_CLOCK 600000000U /*!< Core clock frequency: 600000000Hz */ + +/*! @brief Arm PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_arm_pll_config_t armPllConfig_BOARD_BootClockRUN; +/*! @brief Usb1 PLL set for BOARD_BootClockRUN configuration. + */ +extern const clock_usb_pll_config_t usb1PllConfig_BOARD_BootClockRUN; +/*! @brief Sys PLL for BOARD_BootClockRUN configuration. + */ +extern const clock_sys_pll_config_t sysPllConfig_BOARD_BootClockRUN; + +/******************************************************************************* + * API for BOARD_BootClockRUN configuration + ******************************************************************************/ +#if defined(__cplusplus) +extern "C" { +#endif /* __cplusplus*/ + +/*! + * @brief This function executes configuration of clocks. + * + */ +void BOARD_BootClockRUN(void); + +#if defined(__cplusplus) +} +#endif /* __cplusplus*/ + +#endif /* _CLOCK_CONFIG_H_ */ + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.c b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.c new file mode 100644 index 000000000..bc1567915 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.c @@ -0,0 +1,691 @@ +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +!!GlobalInfo +product: Pins v5.0 +processor: MIMXRT1052xxxxB +package_id: MIMXRT1052DVL6B +mcu_data: ksdk2_0 +processor_version: 5.0.2 +board: IMXRT1050-EVKB +pin_labels: +- {pin_num: G11, pin_signal: GPIO_AD_B0_03, label: BSP_BEEP} +- {pin_num: L13, pin_signal: GPIO_AD_B1_10, label: BSP_RS485_RE, identifier: CSI_D7} +- {pin_num: J13, pin_signal: GPIO_AD_B1_11, label: BSP_DS18B20, identifier: CSI_D6} +- {pin_num: K12, pin_signal: GPIO_AD_B1_05, label: BSP_AP3216C_INT, identifier: CSI_MCLK} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +#include "fsl_common.h" +#include "fsl_iomuxc.h" +#include "pin_mux.h" + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitBootPins + * Description : Calls initialization functions. + * + * END ****************************************************************************************************************/ +void BOARD_InitBootPins(void) { +} + +/* + * TEXT BELOW IS USED AS SETTING FOR TOOLS ************************************* +BOARD_InitPins: +- options: {callFromInitBoot: 'false', coreID: core0, enableClock: 'true'} +- pin_list: + - {pin_num: K14, peripheral: LPUART1, signal: TX, pin_signal: GPIO_AD_B0_12} + - {pin_num: L14, peripheral: LPUART1, signal: RX, pin_signal: GPIO_AD_B0_13} + - {pin_num: L11, peripheral: LPUART2, signal: TX, pin_signal: GPIO_AD_B1_02} + - {pin_num: M12, peripheral: LPUART2, signal: RX, pin_signal: GPIO_AD_B1_03} + - {pin_num: D13, peripheral: LPUART5, signal: TX, pin_signal: GPIO_B1_12} + - {pin_num: D14, peripheral: LPUART5, signal: RX, pin_signal: GPIO_B1_13} + - {pin_num: H13, peripheral: PWM4, signal: 'A, 0', pin_signal: GPIO_AD_B1_08} + - {pin_num: M13, peripheral: PWM4, signal: 'A, 1', pin_signal: GPIO_AD_B1_09} + - {pin_num: G13, peripheral: PWM1, signal: 'A, 3', pin_signal: GPIO_AD_B0_10} + - {pin_num: J11, peripheral: LPI2C1, signal: SCL, pin_signal: GPIO_AD_B1_00, software_input_on: Enable} + - {pin_num: K11, peripheral: LPI2C1, signal: SDA, pin_signal: GPIO_AD_B1_01, software_input_on: Enable} + - {pin_num: L13, peripheral: GPIO1, signal: 'gpio_io, 26', pin_signal: GPIO_AD_B1_10} + - {pin_num: G11, peripheral: GPIO1, signal: 'gpio_io, 03', pin_signal: GPIO_AD_B0_03} + - {pin_num: J13, peripheral: GPIO1, signal: 'gpio_io, 27', pin_signal: GPIO_AD_B1_11} + - {pin_num: K12, peripheral: GPIO1, signal: 'gpio_io, 21', pin_signal: GPIO_AD_B1_05} + * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS *********** + */ + +/* FUNCTION ************************************************************************************************************ + * + * Function Name : BOARD_InitPins + * Description : Configures pin routing and optionally pin electrical features. + * + * END ****************************************************************************************************************/ +void BOARD_InitPins(void) +{ + CLOCK_EnableClock(kCLOCK_Iomuxc); /* iomuxc clock (iomuxc_clk_enable): 0x03U */ + + /*CH438 IO initialize + IOMUXC_SetPinMux( + IOMUXC_GPIO_SD_B1_05_GPIO3_IO05, /* GPIO3_IO05 is configured as CH438_nRD + 0U);*/ + + /* uart 1 2 3 4 8 io initialize */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 is configured as LPUART1_TX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 is configured as LPUART1_RX */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_12_LPUART1_TX, /* GPIO_AD_B0_12 PAD functional properties : */ + 0x10B0u); /* Slew Rate Field: Slow Slew Rate*/ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B0_13_LPUART1_RX, /* GPIO_AD_B0_13 PAD functional properties : */ + 0x10B0u); + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_02_LPUART2_TX, + 0U); + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_03_LPUART2_RX, + 0U); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_02_LPUART2_TX, + 0x10B0u); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_03_LPUART2_RX, + 0x10B0u); + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_06_LPUART3_TX, + 0U); + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_07_LPUART3_RX, + 0U); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_06_LPUART3_TX, + 0x10B0u); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_07_LPUART3_RX, + 0x10B0u); + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_00_LPUART4_TX, + 0U); + IOMUXC_SetPinMux( + IOMUXC_GPIO_B1_01_LPUART4_RX, + 0U); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_00_LPUART4_TX, + 0x10B0u); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_B1_01_LPUART4_RX, + 0x10B0u); + + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_10_LPUART8_TX, + 0U); + IOMUXC_SetPinMux( + IOMUXC_GPIO_AD_B1_11_LPUART8_RX, + 0U); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_10_LPUART8_TX, + 0x10B0u); + IOMUXC_SetPinConfig( + IOMUXC_GPIO_AD_B1_11_LPUART8_RX, + 0x10B0u); + + /* Semc io initialize sdram can used*/ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_00_SEMC_DATA00, /* GPIO_EMC_00 is configured as SEMC_DATA00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_01_SEMC_DATA01, /* GPIO_EMC_01 is configured as SEMC_DATA01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_02_SEMC_DATA02, /* GPIO_EMC_02 is configured as SEMC_DATA02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_03_SEMC_DATA03, /* GPIO_EMC_03 is configured as SEMC_DATA03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_04_SEMC_DATA04, /* GPIO_EMC_04 is configured as SEMC_DATA04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_05_SEMC_DATA05, /* GPIO_EMC_05 is configured as SEMC_DATA05 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_06_SEMC_DATA06, /* GPIO_EMC_06 is configured as SEMC_DATA06 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_07_SEMC_DATA07, /* GPIO_EMC_07 is configured as SEMC_DATA07 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_08_SEMC_DM00, /* GPIO_EMC_08 is configured as SEMC_DM00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_09_SEMC_ADDR00, /* GPIO_EMC_09 is configured as SEMC_ADDR00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_10_SEMC_ADDR01, /* GPIO_EMC_10 is configured as SEMC_ADDR01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_11_SEMC_ADDR02, /* GPIO_EMC_11 is configured as SEMC_ADDR02 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_12_SEMC_ADDR03, /* GPIO_EMC_12 is configured as SEMC_ADDR03 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_13_SEMC_ADDR04, /* GPIO_EMC_13 is configured as SEMC_ADDR04 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_14_SEMC_ADDR05, /* GPIO_EMC_14 is configured as SEMC_ADDR05 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_15_SEMC_ADDR06, /* GPIO_EMC_15 is configured as SEMC_ADDR06 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_16_SEMC_ADDR07, /* GPIO_EMC_16 is configured as SEMC_ADDR07 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_17_SEMC_ADDR08, /* GPIO_EMC_17 is configured as SEMC_ADDR08 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_18_SEMC_ADDR09, /* GPIO_EMC_18 is configured as SEMC_ADDR09 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_19_SEMC_ADDR11, /* GPIO_EMC_19 is configured as SEMC_ADDR11 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_20_SEMC_ADDR12, /* GPIO_EMC_20 is configured as SEMC_ADDR12 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_21_SEMC_BA0, /* GPIO_EMC_21 is configured as SEMC_BA0 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_22_SEMC_BA1, /* GPIO_EMC_22 is configured as SEMC_BA1 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_23_SEMC_ADDR10, /* GPIO_EMC_23 is configured as SEMC_ADDR10 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_24_SEMC_CAS, /* GPIO_EMC_24 is configured as SEMC_CAS */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_25_SEMC_RAS, /* GPIO_EMC_25 is configured as SEMC_RAS */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_26_SEMC_CLK, /* GPIO_EMC_26 is configured as SEMC_CLK */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_27_SEMC_CKE, /* GPIO_EMC_27 is configured as SEMC_CKE */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_28_SEMC_WE, /* GPIO_EMC_28 is configured as SEMC_WE */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_29_SEMC_CS0, /* GPIO_EMC_29 is configured as SEMC_CS0 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_30_SEMC_DATA08, /* GPIO_EMC_30 is configured as SEMC_DATA08 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_31_SEMC_DATA09, /* GPIO_EMC_31 is configured as SEMC_DATA09 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_32_SEMC_DATA10, /* GPIO_EMC_32 is configured as SEMC_DATA10 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_33_SEMC_DATA11, /* GPIO_EMC_33 is configured as SEMC_DATA11 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_34_SEMC_DATA12, /* GPIO_EMC_34 is configured as SEMC_DATA12 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_35_SEMC_DATA13, /* GPIO_EMC_35 is configured as SEMC_DATA13 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_36_SEMC_DATA14, /* GPIO_EMC_36 is configured as SEMC_DATA14 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_37_SEMC_DATA15, /* GPIO_EMC_37 is configured as SEMC_DATA15 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_38_SEMC_DM01, /* GPIO_EMC_38 is configured as SEMC_DM01 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_39_SEMC_DQS, /* GPIO_EMC_39 is configured as SEMC_DQS */ + 1U); /* Software Input On Field: Force input path of pad GPIO_EMC_39 */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_40_SEMC_RDY, /* GPIO_EMC_40 is configured as SEMC_RDY */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + IOMUXC_SetPinMux( + IOMUXC_GPIO_EMC_41_SEMC_CSX00, /* GPIO_EMC_41 is configured as SEMC_CSX00 */ + 0U); /* Software Input On Field: Input Path is determined by functionality */ + + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_00_SEMC_DATA00, /* GPIO_EMC_00 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_01_SEMC_DATA01, /* GPIO_EMC_01 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_02_SEMC_DATA02, /* GPIO_EMC_02 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_03_SEMC_DATA03, /* GPIO_EMC_03 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_04_SEMC_DATA04, /* GPIO_EMC_04 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_05_SEMC_DATA05, /* GPIO_EMC_05 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_06_SEMC_DATA06, /* GPIO_EMC_06 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_07_SEMC_DATA07, /* GPIO_EMC_07 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_08_SEMC_DM00, /* GPIO_EMC_08 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_09_SEMC_ADDR00, /* GPIO_EMC_09 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_10_SEMC_ADDR01, /* GPIO_EMC_10 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_11_SEMC_ADDR02, /* GPIO_EMC_11 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_12_SEMC_ADDR03, /* GPIO_EMC_12 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_13_SEMC_ADDR04, /* GPIO_EMC_13 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_14_SEMC_ADDR05, /* GPIO_EMC_14 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_15_SEMC_ADDR06, /* GPIO_EMC_15 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_16_SEMC_ADDR07, /* GPIO_EMC_16 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_17_SEMC_ADDR08, /* GPIO_EMC_17 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_18_SEMC_ADDR09, /* GPIO_EMC_18 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_19_SEMC_ADDR11, /* GPIO_EMC_19 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_20_SEMC_ADDR12, /* GPIO_EMC_20 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_21_SEMC_BA0, /* GPIO_EMC_21 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_22_SEMC_BA1, /* GPIO_EMC_22 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_23_SEMC_ADDR10, /* GPIO_EMC_23 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_24_SEMC_CAS, /* GPIO_EMC_24 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_25_SEMC_RAS, /* GPIO_EMC_25 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_26_SEMC_CLK, /* GPIO_EMC_26 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_27_SEMC_CKE, /* GPIO_EMC_27 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_28_SEMC_WE, /* GPIO_EMC_28 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_29_SEMC_CS0, /* GPIO_EMC_29 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_30_SEMC_DATA08, /* GPIO_EMC_30 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_31_SEMC_DATA09, /* GPIO_EMC_31 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_32_SEMC_DATA10, /* GPIO_EMC_32 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_33_SEMC_DATA11, /* GPIO_EMC_33 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_34_SEMC_DATA12, /* GPIO_EMC_34 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_35_SEMC_DATA13, /* GPIO_EMC_35 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_36_SEMC_DATA14, /* GPIO_EMC_36 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_37_SEMC_DATA15, /* GPIO_EMC_37 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_38_SEMC_DM01, /* GPIO_EMC_38 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_39_SEMC_DQS, /* GPIO_EMC_39 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_40_SEMC_RDY, /* GPIO_EMC_40 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + IOMUXC_SetPinConfig( + IOMUXC_GPIO_EMC_41_SEMC_CSX00, /* GPIO_EMC_41 PAD functional properties : */ + 0x0110F9u); /* Slew Rate Field: Fast Slew Rate + Drive Strength Field: R0/7 + Speed Field: max(200MHz) + Open Drain Enable Field: Open Drain Disabled + Pull / Keep Enable Field: Pull/Keeper Enabled + Pull / Keep Select Field: Keeper + Pull Up / Down Config. Field: 100K Ohm Pull Down + Hyst. Enable Field: Hysteresis Enabled */ + + +} + +/*********************************************************************************************************************** + * EOF + **********************************************************************************************************************/ diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.h new file mode 100644 index 000000000..b6aa2b3da --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MCUX_Config/pin_mux.h @@ -0,0 +1,75 @@ +/*********************************************************************************************************************** + * This file was generated by the MCUXpresso Config Tools. Any manual edits made to this file + * will be overwritten if the respective MCUXpresso Config Tools is used to update this file. + **********************************************************************************************************************/ + +#ifndef _PIN_MUX_H_ +#define _PIN_MUX_H_ + +/*********************************************************************************************************************** + * Definitions + **********************************************************************************************************************/ + +/*! @brief Direction type */ +typedef enum _pin_mux_direction +{ + kPIN_MUX_DirectionInput = 0U, /* Input direction */ + kPIN_MUX_DirectionOutput = 1U, /* Output direction */ + kPIN_MUX_DirectionInputOrOutput = 2U /* Input or output direction */ +} pin_mux_direction_t; + +/*! + * @addtogroup pin_mux + * @{ + */ + +/*********************************************************************************************************************** + * API + **********************************************************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @brief Calls initialization functions. + * + */ +void BOARD_InitBootPins(void); + +/* GPIO_AD_B0_12 (coord K14), UART1_TXD */ +#define BOARD_INITPINS_UART1_TXD_PERIPHERAL LPUART1 /*!< Device name: LPUART1 */ +#define BOARD_INITPINS_UART1_TXD_SIGNAL TX /*!< LPUART1 signal: TX */ + +/* GPIO_AD_B0_13 (coord L14), UART1_RXD */ +#define BOARD_INITPINS_UART1_RXD_PERIPHERAL LPUART1 /*!< Device name: LPUART1 */ +#define BOARD_INITPINS_UART1_RXD_SIGNAL RX /*!< LPUART1 signal: RX */ + +/* GPIO_AD_B1_02 (coord L11), SPDIF_OUT/J22[7] */ +#define BOARD_INITPINS_SPDIF_OUT_PERIPHERAL LPUART2 /*!< Device name: LPUART2 */ +#define BOARD_INITPINS_SPDIF_OUT_SIGNAL TX /*!< LPUART2 signal: TX */ + +/* GPIO_AD_B1_03 (coord M12), SPDIF_IN/J22[8] */ +#define BOARD_INITPINS_SPDIF_IN_PERIPHERAL LPUART2 /*!< Device name: LPUART2 */ +#define BOARD_INITPINS_SPDIF_IN_SIGNAL RX /*!< LPUART2 signal: RX */ + + + +/*! + * @brief Configures pin routing and optionally pin electrical features. + * + */ +void BOARD_InitPins(void); + +#if defined(__cplusplus) +} +#endif + +/*! + * @} + */ +#endif /* _PIN_MUX_H_ */ + +/*********************************************************************************************************************** + * EOF + **********************************************************************************************************************/ diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MIMXRT_QSPIFLASH.FLM b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/MIMXRT_QSPIFLASH.FLM new file mode 100644 index 0000000000000000000000000000000000000000..097d6c449bcfec59f95b4f6f0d4a62d85351bf39 GIT binary patch literal 1353716 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�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%0AnecF!y*M-0 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%0D(FZ@q>FzV_c#Yd&W!%km=|lDUvzGQ=nMv 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

^7J@B*{C*jJnsN0UGt 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 +#include +#include "board.h" +#include "pin_mux.h" + +#ifdef BSP_USING_DMA +#include "fsl_dmamux.h" +#include "fsl_edma.h" +#endif + +#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 + 3 bits for subpriority */ +#define NVIC_PRIORITYGROUP_2 0x00000005U /*!< 2 bits for pre-emption priority + 2 bits for subpriority */ +#define NVIC_PRIORITYGROUP_3 0x00000004U /*!< 3 bits for pre-emption priority + 1 bits for subpriority */ +#define NVIC_PRIORITYGROUP_4 0x00000003U /*!< 4 bits for pre-emption priority + 0 bits for subpriority */ + +/* MPU configuration. */ +static void BOARD_ConfigMPU(void) +{ + /* Disable I cache and D cache */ + SCB_DisableICache(); + SCB_DisableDCache(); + + /* Disable MPU */ + ARM_MPU_Disable(); + + /* Region 0 setting */ + MPU->RBAR = ARM_MPU_RBAR(0, 0xC0000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_512MB); + + /* Region 1 setting */ + MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB); + + /* Region 2 setting */ + // spi flash: normal type, cacheable, no bufferable, no shareable + MPU->RBAR = ARM_MPU_RBAR(2, 0x60000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_512MB); + + /* Region 3 setting */ + MPU->RBAR = ARM_MPU_RBAR(3, 0x00000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_1GB); + + /* Region 4 setting */ + MPU->RBAR = ARM_MPU_RBAR(4, 0x00000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); + + /* Region 5 setting */ + MPU->RBAR = ARM_MPU_RBAR(5, 0x20000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_128KB); + + /* Region 6 setting */ + MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB); + +#if defined(BSP_USING_SDRAM) + /* Region 7 setting */ + MPU->RBAR = ARM_MPU_RBAR(7, 0x80000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_32MB); + + /* Region 8 setting */ + MPU->RBAR = ARM_MPU_RBAR(8, 0x81E00000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 1, 1, 0, 0, 0, ARM_MPU_REGION_SIZE_2MB); +#endif + + /* Enable MPU */ + ARM_MPU_Enable(MPU_CTRL_PRIVDEFENA_Msk); + + /* Enable I cache and D cache */ + SCB_EnableDCache(); + SCB_EnableICache(); +} + + +/* This is the timer interrupt service routine. */ +void SysTick_Handler(void) +{ + /* enter interrupt */ + rt_interrupt_enter(); + + rt_tick_increase(); + + /* leave interrupt */ + rt_interrupt_leave(); +} + +#ifdef BSP_USING_DMA +void imxrt_dma_init(void) +{ + edma_config_t config; + + DMAMUX_Init(DMAMUX); + EDMA_GetDefaultConfig(&config); + EDMA_Init(DMA0, &config); +} +#endif + +void rt_hw_board_init() +{ + BOARD_ConfigMPU(); + BOARD_InitPins(); + BOARD_BootClockRUN(); + + NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); + SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); + +#ifdef BSP_USING_DMA + imxrt_dma_init(); +#endif + +#ifdef RT_USING_HEAP + rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END); +#endif + +#ifdef RT_USING_COMPONENTS_INIT + rt_components_board_init(); +#endif + +#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) + rt_console_set_device(RT_CONSOLE_DEVICE_NAME); +#endif +} + +void rt_hw_us_delay(rt_uint32_t usec) +{ + ; +} diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/board.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/board.h new file mode 100644 index 000000000..100b932eb --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/board.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2009-09-22 Bernard add board.h to this bsp + */ + +// <<< Use Configuration Wizard in Context Menu >>> +#ifndef __BOARD_H__ +#define __BOARD_H__ + +#include "fsl_common.h" +#include "clock_config.h" + +#ifdef __CC_ARM +extern int Image$$RTT_HEAP$$ZI$$Base; +extern int Image$$RTT_HEAP$$ZI$$Limit; +#define HEAP_BEGIN (&Image$$RTT_HEAP$$ZI$$Base) +#define HEAP_END (&Image$$RTT_HEAP$$ZI$$Limit) + +#elif __ICCARM__ +#pragma section="HEAP" +#define HEAP_BEGIN (__segment_end("HEAP")) +extern void __RTT_HEAP_END; +#define HEAP_END (&__RTT_HEAP_END) + +#else +extern int heap_start; +extern int heap_end; +#define HEAP_BEGIN (&heap_start) +#define HEAP_END (&heap_end) +#endif + +#define HEAP_SIZE ((uint32_t)HEAP_END - (uint32_t)HEAP_BEGIN) + +void rt_hw_board_init(void); + +#endif + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.icf b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.icf new file mode 100644 index 000000000..8acfc82bf --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.icf @@ -0,0 +1,95 @@ +/* +** ################################################################### +** Processors: MIMXRT1052CVJ5B +** MIMXRT1052CVL5B +** MIMXRT1052DVJ6B +** MIMXRT1052DVL6B +** +** Compiler: IAR ANSI C/C++ Compiler for ARM +** Reference manual: IMXRT1050RM Rev.1, 03/2018 +** Version: rev. 1.0, 2018-09-21 +** Build: b180921 +** +** Abstract: +** Linker file for the IAR ANSI C/C++ Compiler for ARM +** +** Copyright 2016 Freescale Semiconductor, Inc. +** Copyright 2016-2018 NXP +** All rights reserved. +** +** SPDX-License-Identifier: BSD-3-Clause +** +** http: www.nxp.com +** mail: support@nxp.com +** +** ################################################################### +*/ + +define symbol m_interrupts_start = 0x60002000; +define symbol m_interrupts_end = 0x600023FF; + +define symbol m_text_start = 0x60002400; +define symbol m_text_end = 0x61FFFFFF; + +define symbol m_data_start = 0x20000000; +define symbol m_data_end = 0x2001FFFF; + +define symbol m_data2_start = 0x20200000; +define symbol m_data2_end = 0x2023FFFF; + +define exported symbol m_boot_hdr_conf_start = 0x60000000; +define symbol m_boot_hdr_ivt_start = 0x60001000; +define symbol m_boot_hdr_boot_data_start = 0x60001020; +define symbol m_boot_hdr_dcd_data_start = 0x60001030; + +/* Sizes */ +if (isdefinedsymbol(__stack_size__)) { + define symbol __size_cstack__ = __stack_size__; +} else { + define symbol __size_cstack__ = 0x0400; +} + +if (isdefinedsymbol(__heap_size__)) { + define symbol __size_heap__ = __heap_size__; +} else { + define symbol __size_heap__ = 0x0400; +} + +define exported symbol __VECTOR_TABLE = m_interrupts_start; +define exported symbol __VECTOR_RAM = m_interrupts_start; +define exported symbol __RAM_VECTOR_TABLE_SIZE = 0x0; +define exported symbol __RTT_HEAP_END = m_data2_end; + +define memory mem with size = 4G; +define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end] + | mem:[from m_text_start to m_text_end]; + +define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__]; +define region DATA2_region = mem:[from m_data2_start to m_data2_end]; +define region CSTACK_region = mem:[from m_data_end-__size_cstack__+1 to m_data_end]; + +define block CSTACK with alignment = 8, size = __size_cstack__ { }; +define block HEAP with alignment = 8, size = __size_heap__ { }; +define block RW { readwrite }; +define block ZI { zi }; +define block NCACHE_VAR { section NonCacheable , section NonCacheable.init }; + +initialize by copy { readwrite, section .textrw }; +do not initialize { section .noinit }; + +place at address mem: m_interrupts_start { readonly section .intvec }; + +place at address mem:m_boot_hdr_conf_start { section .boot_hdr.conf }; +place at address mem:m_boot_hdr_ivt_start { section .boot_hdr.ivt }; +place at address mem:m_boot_hdr_boot_data_start { readonly section .boot_hdr.boot_data }; +place at address mem:m_boot_hdr_dcd_data_start { readonly section .boot_hdr.dcd_data }; + +keep{ section .boot_hdr.conf, section .boot_hdr.ivt, section .boot_hdr.boot_data, section .boot_hdr.dcd_data }; + +place in TEXT_region { readonly }; +place in DATA_region { block RW }; +place in DATA_region { block ZI }; +place in DATA_region { last block HEAP }; +place in DATA_region { block NCACHE_VAR }; +place in CSTACK_region { block CSTACK }; + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.lds b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.lds new file mode 100644 index 000000000..b8c229ae3 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.lds @@ -0,0 +1,276 @@ +/* +** ################################################################### +** Processors: MIMXRT1052CVL5A +** MIMXRT1052DVL6A +** +** Compiler: GNU C Compiler +** Reference manual: IMXRT1050RM Rev.C, 08/2017 +** Version: rev. 0.1, 2017-01-10 +** Build: b170927 +** +** Abstract: +** Linker file for the GNU C Compiler +** +** Copyright 2016 Freescale Semiconductor, Inc. +** Copyright 2016-2017 NXP +** 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. Neither the name of the copyright holder nor the names of its +** contributors may be used to endorse or promote products derived from this +** software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. +** +** http: www.nxp.com +** mail: support@nxp.com +** +** ################################################################### +*/ + +/* Entry Point */ +ENTRY(Reset_Handler) + +HEAP_SIZE = DEFINED(__heap_size__) ? __heap_size__ : 0x0400; +STACK_SIZE = DEFINED(__stack_size__) ? __stack_size__ : 0x0400; + +/* Specify the memory areas */ +MEMORY +{ + m_boot_data (RX) : ORIGIN = 0x60000000, LENGTH = 0x00001000 + m_image_vertor_table (RX) : ORIGIN = 0x60001000, LENGTH = 0x00001000 + + m_interrupts (RX) : ORIGIN = 0x60002000, LENGTH = 0x00000400 + m_text (RX) : ORIGIN = 0x60002400, LENGTH = 0x1F7FDC00 + + m_itcm (RW) : ORIGIN = 0x00000000, LENGTH = 0x00020000 + m_dtcm (RW) : ORIGIN = 0x20000000, LENGTH = 0x00020000 + m_ocram (RW) : ORIGIN = 0x20200000, LENGTH = 0x00040000 + + m_sdram (RW) : ORIGIN = 0x80000000, LENGTH = 0x01E00000 + m_nocache (RW) : ORIGIN = 0x81E00000, LENGTH = 0x00200000 +} + +/* Define output sections */ +SECTIONS +{ + .boot_data : + { + KEEP(*(.boot_hdr.conf)) + } > m_boot_data + + .image_vertor_table : + { + KEEP(*(.boot_hdr.ivt)) + KEEP(*(.boot_hdr.boot_data)) + KEEP(*(.boot_hdr.dcd_data)) + } > m_image_vertor_table + + /* The startup code goes first into internal RAM */ + .interrupts : + { + __VECTOR_TABLE = .; + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } > m_interrupts + + __VECTOR_RAM = __VECTOR_TABLE; + __RAM_VECTOR_TABLE_SIZE_BYTES = 0x0; + + /* The program code and other data goes into internal RAM */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + KEEP (*(.init)) + KEEP (*(.fini)) + . = ALIGN(4); + + /* section information for finsh shell */ + . = ALIGN(4); + __fsymtab_start = .; + KEEP(*(FSymTab)) + __fsymtab_end = .; + . = ALIGN(4); + __vsymtab_start = .; + KEEP(*(VSymTab)) + __vsymtab_end = .; + . = ALIGN(4); + + /* section information for initial. */ + . = ALIGN(4); + __rt_init_start = .; + KEEP(*(SORT(.rti_fn*))) + __rt_init_end = .; + } > m_text + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > m_text + + .ARM : + { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } > m_text + + .ctors : + { + PROVIDE(__ctors_start__ = .); + /* __CTOR_LIST__ = .; */ + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + from the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + /* __CTOR_END__ = .; */ + PROVIDE(__ctors_end__ = .); + } > m_text + + .dtors : + { + PROVIDE(__dtors_start__ = .); + /* __DTOR_LIST__ = .; */ + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + /* __DTOR_END__ = .; */ + PROVIDE(__dtors_end__ = .); + } > m_text + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } > m_text + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } > m_text + + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } > m_text + + __etext = .; /* define a global symbol at end of code */ + __DATA_ROM = .; /* Symbol is used by startup for data initialization */ + + .data : AT(__DATA_ROM) + { + . = ALIGN(4); + __DATA_RAM = .; + __data_start__ = .; /* create a global symbol at data start */ + *(m_usb_dma_init_data) + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + KEEP(*(.jcr*)) + . = ALIGN(4); + __data_end__ = .; /* define a global symbol at data end */ + } > m_dtcm + + __NDATA_ROM = __DATA_ROM + (__data_end__ - __data_start__); + .ncache.init : AT(__NDATA_ROM) + { + __noncachedata_start__ = .; /* create a global symbol at ncache data start */ + *(NonCacheable.init) + . = ALIGN(4); + __noncachedata_init_end__ = .; /* create a global symbol at initialized ncache data end */ + } > m_nocache + . = __noncachedata_init_end__; + .ncache : + { + *(NonCacheable) + . = ALIGN(4); + __noncachedata_end__ = .; /* define a global symbol at ncache data end */ + } > m_nocache + + __DATA_END = __NDATA_ROM + (__noncachedata_init_end__ - __noncachedata_start__); + text_end = ORIGIN(m_text) + LENGTH(m_text); + ASSERT(__DATA_END <= text_end, "region m_text overflowed with text and data") + + /* Uninitialized data section */ + .bss : + { + /* This is used by the startup in order to initialize the .bss section */ + . = ALIGN(4); + __START_BSS = .; + __bss_start__ = .; + *(m_usb_dma_noninit_data) + *(.bss) + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + __END_BSS = .; + } > m_dtcm + + .stack : + { + . = ALIGN(8); + stack_start = .; + . += STACK_SIZE; + stack_end = .; + __StackTop = .; + } > m_dtcm + + .RTT_HEAP : + { + heap_start = .; + . = ALIGN(8); + } > m_dtcm + + PROVIDE(heap_end = ORIGIN(m_dtcm) + LENGTH(m_dtcm)); + + .ARM.attributes 0 : { *(.ARM.attributes) } + +} + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.sct b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.sct new file mode 100644 index 000000000..8d8ab008d --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/linker_scripts/link.sct @@ -0,0 +1,134 @@ +#! armcc -E +/* +** ################################################################### +** Processors: MIMXRT1052CVL5A +** MIMXRT1052DVL6A +** +** Compiler: Keil ARM C/C++ Compiler +** Reference manual: IMXRT1050RM Rev.C, 08/2017 +** Version: rev. 0.1, 2017-01-10 +** Build: b170927 +** +** Abstract: +** Linker file for the Keil ARM C/C++ Compiler +** +** Copyright 2016 Freescale Semiconductor, Inc. +** Copyright 2016-2017 NXP +** 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. Neither the name of the copyright holder nor the names of its +** contributors may be used to endorse or promote products derived from this +** software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. +** +** http: www.nxp.com +** mail: support@nxp.com +** +** ################################################################### +*/ +#define m_flash_config_start 0x60000000 +#define m_flash_config_size 0x00001000 + +#define m_ivt_start 0x60001000 +#define m_ivt_size 0x00001000 + +#define m_text_start 0x60002000 +#define m_text_size 0x1F7FE000 + +#define m_data_start 0x20000000 +#define m_data_size 0x00020000 + +#define m_ncache_start 0x81E00000 +#define m_ncache_size 0x00200000 + + +/* Sizes */ +#if (defined(__stack_size__)) + #define Stack_Size __stack_size__ +#else + #define Stack_Size 0x1000 +#endif + +#if (defined(__heap_size__)) + #define Heap_Size __heap_size__ +#else + #define Heap_Size 0x0400 +#endif + + + +#if 1 +LR_m_rom_config m_flash_config_start m_flash_config_size ; load region size_region +{ + RW_m_config_text m_flash_config_start m_flash_config_size ; load address = execution address + { + * (.boot_hdr.conf, +FIRST) + } +} + +LR_m_rom_ivt m_ivt_start m_ivt_size ; load region size_region +{ + RW_m_ivt_text m_ivt_start m_ivt_size ; load address = execution address + { + * (.boot_hdr.ivt, +FIRST) + * (.boot_hdr.boot_data) + * (.boot_hdr.dcd_data) + } +} +#endif + +#define RTT_HEAP_SIZE (m_data_size-ImageLength(RW_m_data)-ImageLength(ARM_LIB_HEAP)-ImageLength(ARM_LIB_STACK)) + +; load region size_region +LR_IROM1 m_text_start m_text_size +{ + ER_IROM1 m_text_start m_text_size ; load address = execution address + { + * (RESET,+FIRST) + * (InRoot$$Sections) + .ANY (+RO) + } + + RW_m_data m_data_start m_data_size-Stack_Size-Heap_Size ; RW data + { + .ANY (+RW +ZI) + } + + ARM_LIB_HEAP +0 EMPTY Heap_Size{} ; Heap region growing up + ARM_LIB_STACK +0 EMPTY Stack_Size{} ; Stack region growing down + RTT_HEAP +0 EMPTY RTT_HEAP_SIZE{} + + ; ncache RW data + RW_m_ncache m_ncache_start m_ncache_size + { + * (NonCacheable.init) + * (NonCacheable) + } + ITCM 0x400 0xFBFF { + ;drv_flexspi_hyper.o(+RO) + ;fsl_flexspi.o(+RO) + * (*CLOCK_DisableClock) + * (*CLOCK_ControlGate) + * (*CLOCK_EnableClock) + * (*CLOCK_SetDiv) + * (itcm) + } +} diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/board/ports/sdram_port.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/ports/sdram_port.h new file mode 100644 index 000000000..6673e369c --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/board/ports/sdram_port.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2006-2018, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2018-12-05 zylx The first version for STM32F4xx + * 2019-4-25 misonyo port to IMXRT + */ + +#ifndef SDRAM_PORT_H__ +#define SDRAM_PORT_H__ + +/* parameters for sdram peripheral */ + +#define SDRAM_BANK_ADDR ((uint32_t)0x80000000U) +/* region#0/1/2/3: kSEMC_SDRAM_CS0/1/2/3 */ +#define SDRAM_REGION kSEMC_SDRAM_CS0 +/* CS pin: kSEMC_MUXCSX0/1/2/3 */ +#define SDRAM_CS_PIN kSEMC_MUXCSX0 +/* size(kbyte):32MB = 32*1024*1KBytes */ +#define SDRAM_SIZE ((uint32_t)0x8000) +/* data width: kSEMC_PortSize8Bit,kSEMC_PortSize16Bit */ +#define SDRAM_DATA_WIDTH kSEMC_PortSize16Bit +/* column bit numbers: kSEMC_SdramColunm_9/10/11/12bit */ +#define SDRAM_COLUMN_BITS kSEMC_SdramColunm_9bit +/* cas latency clock number: kSEMC_LatencyOne/Two/Three */ +#define SDRAM_CAS_LATENCY kSEMC_LatencyThree + +/* Timing configuration for W9825G6KH */ +/* TRP:precharge to active command time (ns) */ +#define SDRAM_TRP 18 +/* TRCD:active to read/write command delay time (ns) */ +#define SDRAM_TRCD 18 +/* The time between two refresh commands,Use the maximum of the (Trfc , Txsr).(ns) */ +#define SDRAM_REFRESH_RECOVERY 67 +/* TWR:write recovery time (ns). */ +#define SDRAM_TWR 12 +/* TRAS:active to precharge command time (ns). */ +#define SDRAM_TRAS 42 +/* TRC time (ns). */ +#define SDRAM_TRC 60 +/* active to active time (ns). */ +#define SDRAM_ACT2ACT 60 +/* refresh time (ns). 64ms */ +#define SDRAM_REFRESH_ROW 64 * 1000000 / 8192 + +#endif /* SDRAM_PORT_H__ */ diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvoptx b/Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvoptx new file mode 100644 index 000000000..0f04e4573 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvoptx @@ -0,0 +1,177 @@ + + + + 1.0 + +

### uVision Project, (C) Keil Software
+ + + *.c + *.s*; *.src; *.a* + *.obj; *.o + *.lib + *.txt; *.h; *.inc; *.md + *.plm + *.cpp + 0 + + + + 0 + 0 + + + + rtthread + 0x4 + ARM-ADS + + 12000000 + + 1 + 1 + 0 + 1 + 0 + + + 1 + 65535 + 0 + 0 + 0 + + + 79 + 66 + 8 + .\build\keil\List\ + + + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + + + 1 + 0 + 1 + + 8 + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 3 + + + + + + + + + + .\flexspi_nor.ini + BIN\CMSIS_AGDI.dll + + + + 0 + CMSIS_AGDI + -X"CMSIS-DAP-v1-MuseLab" -U0700000105dcff343730534243072257 -O974 -S0 -C0 -P00000000 -N00("ARM CoreSight SW-DP") -D00(0BD11477) -L00(0) -TO65554 -TC10000000 -TT10000000 -TP20 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC8000 -FN1 -FF0MIMXRT_QSPIFLASH -FS060000000 -FL02000000 + + + 0 + JL2CM3 + -U30000299 -O78 -S2 -ZTIFSpeedSel5000 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(0BD11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO15 -FD20000000 -FC8000 -FN1 -FF0MIMXRT105x_QuadSPI_4KB_SEC -FS060000000 -FL0800000 -FP0($$Device:MIMXRT1052CVL5B$arm\MIMXRT105x_QuadSPI_4KB_SEC.FLM) + + + + + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + 0 + 0 + 0 + + + + + + + + + + + + diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvprojx b/Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvprojx new file mode 100644 index 000000000..a5d874f6a --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/project.uvprojx @@ -0,0 +1,987 @@ + + + 2.1 +
### uVision Project, (C) Keil Software
+ + + rtthread + 0x4 + ARM-ADS + 5060528::V5.06 update 5 (build 528)::ARMCC + 0 + + + MIMXRT1052DVL6B + NXP + NXP.MIMXRT1052_DFP.10.0.1 + http://mcuxpresso.nxp.com/cmsis_pack/repo/ + IRAM(0x20000000,0x020000) IRAM2(0x00000000,0x020000) XRAM(0x20200000,0x040000) CPUTYPE("Cortex-M7") FPU3(DFPU) CLOCK(12000000) ELITTLE + + + + 0 + $$Device:MIMXRT1052DVL6B$fsl_device_registers.h + + + + + + + + + + $$Device:MIMXRT1052DVL6B$MIMXRT1052.xml + 0 + 0 + + + + + + + 0 + 0 + 0 + 0 + 1 + + .\build\keil\Obj\ + rtthread + 1 + 0 + 0 + 1 + 1 + .\build\keil\List\ + 1 + 0 + 0 + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 1 + 0 + fromelf --bin !L --output rtthread.bin + + 0 + 0 + 0 + 0 + + 0 + + + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + + + 1 + + + SARMCM3.DLL + + DCM.DLL + -pCM7 + SARMCM3.DLL + + TCM.DLL + -pCM7 + + + + 1 + 0 + 0 + 0 + 16 + + + + + 1 + 0 + 0 + 1 + 1 + 4096 + + 1 + BIN\UL2CM3.DLL + + + + + + 0 + + + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + "Cortex-M7" + + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 3 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x20000 + + + 1 + 0x0 + 0x8000 + + + 1 + 0x20200000 + 0x40000 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 0 + 0x20200000 + 0x40000 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x20000 + + + 0 + 0x0 + 0x20000 + + + + + + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + + --library_interface=armcc --library_type=standardlib --diag_suppress=66,1296,186 + SKIP_SYSCLK_INIT, CPU_MIMXRT1052CVL5B, __CLK_TCK=RT_TICK_PER_SECOND, __RTTHREAD__, FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL=1, XIP_EXTERNAL_FLASH=1, EVK_MCIMXRM, RT_USING_ARM_LIBC + + applications;..\..\rt-thread\libcpu\arm\common;..\..\rt-thread\libcpu\arm\cortex-m7;..\..\rt-thread\components\drivers\include;..\..\rt-thread\components\drivers\include;..\..\rt-thread\components\drivers\include;..\..\rt-thread\components\drivers\include;board;board\MCUX_Config;board\ports;..\..\rt-thread\bsp\imxrt\libraries\drivers;..\..\rt-thread\bsp\imxrt\libraries\drivers\config;..\..\rt-thread\components\dfs\include;..\..\rt-thread\components\dfs\filesystems\devfs;..\..\rt-thread\components\finsh;.;..\..\rt-thread\include;..\..\rt-thread\components\libc\compilers\armlibc;..\..\rt-thread\components\libc\compilers\common;..\..\rt-thread\components\libc\compilers\common\nogcc;..\..\rt-thread\components\libc\posix\pthreads;..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\CMSIS\Include;..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052;..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers;..\..\..\..\APP_Framework\Applications\general_functions\list;..\..\..\..\APP_Framework\Framework\knowing\ota;..\..\..\..\APP_Framework\Framework\sensor;..\..\..\..\APP_Framework\Applications;..\..\..\..\APP_Framework\Framework\sensor\altitude\bmp180;..\..\..\..\APP_Framework\Framework\sensor\co2\g8s;..\..\..\..\APP_Framework\Framework\sensor\voice\d124;..\..\..\..\APP_Framework\Framework\sensor\winddirection\qs-fx;..\..\..\..\APP_Framework\Framework\sensor\windspeed\qs-fs;..\..\..\..\APP_Framework\Framework\transform_layer\rtthread;..\..\rt-thread\examples\utest\testcases\kernel;xip + + + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + + + + + + + + + 0 + 0 + 0 + 0 + 1 + 0 + 0x00000000 + 0x10000000 + + .\board\linker_scripts\link.sct + + + --keep=*(.boot_hdr.ivt)--keep=*(.boot_hdr.boot_data)--keep=*(.boot_hdr.dcd_data)--keep=*(.boot_hdr.conf) + + 6314 + + + + + + Applications + + + main.c + 1 + applications\main.c + + + + + CPU + + + div0.c + 1 + ..\..\rt-thread\libcpu\arm\common\div0.c + + + + + showmem.c + 1 + ..\..\rt-thread\libcpu\arm\common\showmem.c + + + + + backtrace.c + 1 + ..\..\rt-thread\libcpu\arm\common\backtrace.c + + + + + cpu_cache.c + 1 + ..\..\rt-thread\libcpu\arm\cortex-m7\cpu_cache.c + + + + + context_rvds.S + 2 + ..\..\rt-thread\libcpu\arm\cortex-m7\context_rvds.S + + + + + cpuport.c + 1 + ..\..\rt-thread\libcpu\arm\cortex-m7\cpuport.c + + + + + DeviceDrivers + + + cputime.c + 1 + ..\..\rt-thread\components\drivers\cputime\cputime.c + + + + + pin.c + 1 + ..\..\rt-thread\components\drivers\misc\pin.c + + + + + serial.c + 1 + ..\..\rt-thread\components\drivers\serial\serial.c + + + + + completion.c + 1 + ..\..\rt-thread\components\drivers\src\completion.c + + + + + waitqueue.c + 1 + ..\..\rt-thread\components\drivers\src\waitqueue.c + + + + + ringbuffer.c + 1 + ..\..\rt-thread\components\drivers\src\ringbuffer.c + + + + + ringblk_buf.c + 1 + ..\..\rt-thread\components\drivers\src\ringblk_buf.c + + + + + workqueue.c + 1 + ..\..\rt-thread\components\drivers\src\workqueue.c + + + + + pipe.c + 1 + ..\..\rt-thread\components\drivers\src\pipe.c + + + + + dataqueue.c + 1 + ..\..\rt-thread\components\drivers\src\dataqueue.c + + + + + Drivers + + + pin_mux.c + 1 + board\MCUX_Config\pin_mux.c + + + + + board.c + 1 + board\board.c + + + + + clock_config.c + 1 + board\MCUX_Config\clock_config.c + + + + + drv_sdram.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\drivers\drv_sdram.c + + + + + drv_gpio.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\drivers\drv_gpio.c + + + + + drv_uart.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\drivers\drv_uart.c + + + + + Filesystem + + + dfs_posix.c + 1 + ..\..\rt-thread\components\dfs\src\dfs_posix.c + + + + + dfs_poll.c + 1 + ..\..\rt-thread\components\dfs\src\dfs_poll.c + + + + + dfs_file.c + 1 + ..\..\rt-thread\components\dfs\src\dfs_file.c + + + + + dfs.c + 1 + ..\..\rt-thread\components\dfs\src\dfs.c + + + + + dfs_fs.c + 1 + ..\..\rt-thread\components\dfs\src\dfs_fs.c + + + + + dfs_select.c + 1 + ..\..\rt-thread\components\dfs\src\dfs_select.c + + + + + devfs.c + 1 + ..\..\rt-thread\components\dfs\filesystems\devfs\devfs.c + + + + + Finsh + + + shell.c + 1 + ..\..\rt-thread\components\finsh\shell.c + + + + + msh.c + 1 + ..\..\rt-thread\components\finsh\msh.c + + + + + msh_file.c + 1 + ..\..\rt-thread\components\finsh\msh_file.c + + + + + cmd.c + 1 + ..\..\rt-thread\components\finsh\cmd.c + + + + + Kernel + + + memheap.c + 1 + ..\..\rt-thread\src\memheap.c + + + + + idle.c + 1 + ..\..\rt-thread\src\idle.c + + + + + timer.c + 1 + ..\..\rt-thread\src\timer.c + + + + + mempool.c + 1 + ..\..\rt-thread\src\mempool.c + + + + + components.c + 1 + ..\..\rt-thread\src\components.c + + + + + ipc.c + 1 + ..\..\rt-thread\src\ipc.c + + + + + device.c + 1 + ..\..\rt-thread\src\device.c + + + + + clock.c + 1 + ..\..\rt-thread\src\clock.c + + + + + thread.c + 1 + ..\..\rt-thread\src\thread.c + + + + + irq.c + 1 + ..\..\rt-thread\src\irq.c + + + + + scheduler.c + 1 + ..\..\rt-thread\src\scheduler.c + + + + + object.c + 1 + ..\..\rt-thread\src\object.c + + + + + kservice.c + 1 + ..\..\rt-thread\src\kservice.c + + + + + libc + + + stdio.c + 1 + ..\..\rt-thread\components\libc\compilers\armlibc\stdio.c + + + + + syscalls.c + 1 + ..\..\rt-thread\components\libc\compilers\armlibc\syscalls.c + + + + + mem_std.c + 1 + ..\..\rt-thread\components\libc\compilers\armlibc\mem_std.c + + + + + libc.c + 1 + ..\..\rt-thread\components\libc\compilers\armlibc\libc.c + + + + + unistd.c + 1 + ..\..\rt-thread\components\libc\compilers\common\unistd.c + + + + + delay.c + 1 + ..\..\rt-thread\components\libc\compilers\common\delay.c + + + + + time.c + 1 + ..\..\rt-thread\components\libc\compilers\common\time.c + + + + + stdlib.c + 1 + ..\..\rt-thread\components\libc\compilers\common\stdlib.c + + + + + mqueue.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\mqueue.c + + + + + pthread_cond.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_cond.c + + + + + semaphore.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\semaphore.c + + + + + pthread_barrier.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_barrier.c + + + + + sched.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\sched.c + + + + + pthread_rwlock.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_rwlock.c + + + + + pthread_attr.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_attr.c + + + + + pthread_spin.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_spin.c + + + + + pthread_mutex.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_mutex.c + + + + + pthread_tls.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread_tls.c + + + + + pthread.c + 1 + ..\..\rt-thread\components\libc\posix\pthreads\pthread.c + + + + + Libraries + + + system_MIMXRT1052.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\system_MIMXRT1052.c + + + + + fsl_gpio.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers\fsl_gpio.c + + + + + fsl_lpuart.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers\fsl_lpuart.c + + + + + fsl_semc.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers\fsl_semc.c + + + + + fsl_clock.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers\fsl_clock.c + + + + + fsl_cache.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers\fsl_cache.c + + + + + fsl_common.c + 1 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\drivers\fsl_common.c + + + + + startup_MIMXRT1052.s + 2 + ..\..\rt-thread\bsp\imxrt\libraries\MIMXRT1050\MIMXRT1052\arm\startup_MIMXRT1052.s + + + + + list + + + double_list.c + 1 + ..\..\..\..\APP_Framework\Applications\general_functions\list\double_list.c + + + + + single_list.c + 1 + ..\..\..\..\APP_Framework\Applications\general_functions\list\single_list.c + + + + + sensor + + + framework_init.c + 1 + ..\..\..\..\APP_Framework\Applications\framework_init.c + + + + + transform + + + transform.c + 1 + ..\..\..\..\APP_Framework\Framework\transform_layer\rtthread\transform.c + + + + + xip + + + fsl_flexspi_nor_boot.c + 1 + xip\fsl_flexspi_nor_boot.c + + + + + fsl_flexspi_nor_flash.c + 1 + xip\fsl_flexspi_nor_flash.c + + + + + + + + + + + +
diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.h new file mode 100644 index 000000000..f85a45db3 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.h @@ -0,0 +1,194 @@ +#ifndef RT_CONFIG_H__ +#define RT_CONFIG_H__ + +/* Automatically generated file; DO NOT EDIT. */ +/* RT-Thread Configuration */ + +#define ROOT_DIR "../../../.." +#define BSP_DIR "." +#define RT_Thread_DIR "../.." +#define RTT_DIR "../../rt-thread" + +/* RT-Thread Kernel */ + +#define RT_NAME_MAX 8 +#define RT_ALIGN_SIZE 4 +#define RT_THREAD_PRIORITY_32 +#define RT_THREAD_PRIORITY_MAX 32 +#define RT_TICK_PER_SECOND 100 +#define RT_USING_OVERFLOW_CHECK +#define RT_USING_HOOK +#define RT_USING_IDLE_HOOK +#define RT_IDLE_HOOK_LIST_SIZE 4 +#define IDLE_THREAD_STACK_SIZE 256 + +/* kservice optimization */ + +#define RT_KSERVICE_USING_STDLIB +#define RT_DEBUG +#define RT_DEBUG_COLOR + +/* Inter-Thread communication */ + +#define RT_USING_SEMAPHORE +#define RT_USING_MUTEX +#define RT_USING_EVENT +#define RT_USING_MAILBOX +#define RT_USING_MESSAGEQUEUE + +/* Memory Management */ + +#define RT_USING_MEMPOOL +#define RT_USING_MEMHEAP +#define RT_USING_MEMHEAP_AUTO_BINDING +#define RT_USING_MEMHEAP_AS_HEAP +#define RT_USING_HEAP + +/* Kernel Device Object */ + +#define RT_USING_DEVICE +#define RT_USING_CONSOLE +#define RT_CONSOLEBUF_SIZE 128 +#define RT_CONSOLE_DEVICE_NAME "uart1" +#define RT_VER_NUM 0x40004 + +/* RT-Thread Components */ + +#define RT_USING_COMPONENTS_INIT +#define RT_USING_USER_MAIN +#define RT_MAIN_THREAD_STACK_SIZE 2048 +#define RT_MAIN_THREAD_PRIORITY 10 + +/* C++ features */ + + +/* Command shell */ + +#define RT_USING_FINSH +#define RT_USING_MSH +#define FINSH_USING_MSH +#define FINSH_THREAD_NAME "tshell" +#define FINSH_THREAD_PRIORITY 20 +#define FINSH_THREAD_STACK_SIZE 4096 +#define FINSH_USING_HISTORY +#define FINSH_HISTORY_LINES 5 +#define FINSH_USING_SYMTAB +#define FINSH_CMD_SIZE 80 +#define MSH_USING_BUILT_IN_COMMANDS +#define FINSH_USING_DESCRIPTION +#define FINSH_ARG_MAX 10 + +/* Device virtual file system */ + +#define RT_USING_DFS +#define DFS_USING_WORKDIR +#define DFS_FILESYSTEMS_MAX 4 +#define DFS_FILESYSTEM_TYPES_MAX 4 +#define DFS_FD_MAX 16 +#define RT_USING_DFS_DEVFS + +/* Device Drivers */ + +#define RT_USING_DEVICE_IPC +#define RT_PIPE_BUFSZ 512 +#define RT_USING_SERIAL +#define RT_USING_SERIAL_V1 +#define RT_SERIAL_USING_DMA +#define RT_SERIAL_RB_BUFSZ 64 +#define RT_USING_CPUTIME +#define RT_USING_PIN + +/* Using USB */ + + +/* POSIX layer and C standard library */ + +#define RT_USING_LIBC +#define RT_USING_PTHREADS +#define PTHREAD_NUM_MAX 8 +#define RT_USING_POSIX +#define RT_LIBC_USING_TIME +#define RT_LIBC_DEFAULT_TIMEZONE 8 + +/* Network */ + +/* Socket abstraction layer */ + + +/* Network interface device */ + + +/* light weight TCP/IP stack */ + + +/* AT commands */ + + +/* VBUS(Virtual Software BUS) */ + + +/* Utilities */ + + +/* RT-Thread Utestcases */ + + +/* Hardware Drivers Config */ + +#define SOC_IMXRT1052CVL5B + +/* On-chip Peripheral Drivers */ + +#define BSP_USING_BOOT_IMAGE +#define BSP_USING_GPIO +#define BSP_USING_LPUART +#define BSP_USING_LPUART1 + +/* Onboard Peripheral Drivers */ + +#define BSP_USING_SDRAM + +/* MicroPython */ + + +/* More Drivers */ + + +/* APP_Framework */ + +/* Framework */ + +#define TRANSFORM_LAYER_ATTRIUBUTE +#define ADD_RTTHREAD_FETURES + +/* Security */ + + +/* Applications */ + +/* config stack size and priority of main task */ + +#define MAIN_KTASK_STACK_SIZE 1024 + +/* ota app */ + + +/* test app */ + + +/* connection app */ + + +/* control app */ + +/* knowing app */ + + +/* sensor app */ + + +/* lib */ + +#define APP_SELECT_NEWLIB + +#endif diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.py b/Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.py new file mode 100644 index 000000000..02b8e1933 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/rtconfig.py @@ -0,0 +1,162 @@ +import os +import sys + +# toolchains options +ARCH='arm' +CPU='cortex-m7' +CROSS_TOOL='gcc' + +# bsp lib config +BSP_LIBRARY_TYPE = None + +if os.getenv('RTT_CC'): + CROSS_TOOL = os.getenv('RTT_CC') +if os.getenv('RTT_ROOT'): + RTT_ROOT = os.getenv('RTT_ROOT') + +# cross_tool provides the cross compiler +# EXEC_PATH is the compiler execute path, for example, CodeSourcery, Keil MDK, IAR +if CROSS_TOOL == 'gcc': + PLATFORM = 'gcc' + EXEC_PATH = r'C:\Users\XXYYZZ' +elif CROSS_TOOL == 'keil': + PLATFORM = 'armcc' + EXEC_PATH = r'C:/Keil_v5' +elif CROSS_TOOL == 'iar': + PLATFORM = 'iar' + EXEC_PATH = r'C:/Program Files (x86)/IAR Systems/Embedded Workbench 8.0' + +if os.getenv('RTT_EXEC_PATH'): + EXEC_PATH = os.getenv('RTT_EXEC_PATH') + +#BUILD = 'debug' +BUILD = 'release' + +if PLATFORM == 'gcc': + PREFIX = 'arm-none-eabi-' + CC = PREFIX + 'gcc' + CXX = PREFIX + 'g++' + AS = PREFIX + 'gcc' + AR = PREFIX + 'ar' + LINK = PREFIX + 'gcc' + TARGET_EXT = 'elf' + SIZE = PREFIX + 'size' + OBJDUMP = PREFIX + 'objdump' + OBJCPY = PREFIX + 'objcopy' + STRIP = PREFIX + 'strip' + + DEVICE = ' -mcpu=' + CPU + ' -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -ffunction-sections -fdata-sections' + CFLAGS = DEVICE + ' -Wall -D__FPU_PRESENT -eentry' + AFLAGS = ' -c' + DEVICE + ' -x assembler-with-cpp -Wa,-mimplicit-it=thumb -D__START=entry' + LFLAGS = DEVICE + ' -lm -lgcc -lc' + ' -nostartfiles -Wl,--gc-sections,-Map=rtthread.map,-cref,-u,Reset_Handler -T board/linker_scripts/link.lds' + + CPATH = '' + LPATH = '' + + if BUILD == 'debug': + CFLAGS += ' -gdwarf-2' + AFLAGS += ' -gdwarf-2' + CFLAGS += ' -O0' + else: + CFLAGS += ' -O2 -Os' + + POST_ACTION = OBJCPY + ' -O binary $TARGET rtthread.bin\n' + SIZE + ' $TARGET \n' + + # module setting + CXXFLAGS = ' -Woverloaded-virtual -fno-exceptions -fno-rtti ' + M_CFLAGS = CFLAGS + ' -mlong-calls -fPIC ' + M_CXXFLAGS = CXXFLAGS + ' -mlong-calls -fPIC' + M_LFLAGS = DEVICE + CXXFLAGS + ' -Wl,--gc-sections,-z,max-page-size=0x4' +\ + ' -shared -fPIC -nostartfiles -static-libgcc' + M_POST_ACTION = STRIP + ' -R .hash $TARGET\n' + SIZE + ' $TARGET \n' + +elif PLATFORM == 'armcc': + CC = 'armcc' + CXX = 'armcc' + AS = 'armasm' + AR = 'armar' + LINK = 'armlink' + TARGET_EXT = 'axf' + + DEVICE = ' --cpu ' + CPU + '.fp.sp' + CFLAGS = DEVICE + ' --apcs=interwork' + AFLAGS = DEVICE + LFLAGS = DEVICE + ' --libpath "' + EXEC_PATH + '\ARM\ARMCC\lib" --info sizes --info totals --info unused --info veneers --list rtthread.map --scatter "board\linker_scripts\link.sct"' + + CFLAGS += ' --diag_suppress=66,1296,186,6134' + CFLAGS += ' -I' + EXEC_PATH + '/ARM/RV31/INC' + LFLAGS += ' --libpath ' + EXEC_PATH + '/ARM/RV31/LIB' + + EXEC_PATH += '/arm/bin40/' + + if BUILD == 'debug': + CFLAGS += ' -g -O0' + AFLAGS += ' -g' + else: + CFLAGS += ' -O2' + + CXXFLAGS = CFLAGS + CFLAGS += ' --c99' + + POST_ACTION = 'fromelf -z $TARGET' + # POST_ACTION = 'fromelf --bin $TARGET --output rtthread.bin \nfromelf -z $TARGET' + +elif PLATFORM == 'iar': + CC = 'iccarm' + CXX = 'iccarm' + AS = 'iasmarm' + AR = 'iarchive' + LINK = 'ilinkarm' + TARGET_EXT = 'out' + + DEVICE = ' -D__FPU_PRESENT' + + CFLAGS = DEVICE + CFLAGS += ' --diag_suppress Pa050' + CFLAGS += ' --no_cse' + CFLAGS += ' --no_unroll' + CFLAGS += ' --no_inline' + CFLAGS += ' --no_code_motion' + CFLAGS += ' --no_tbaa' + CFLAGS += ' --no_clustering' + CFLAGS += ' --no_scheduling' + CFLAGS += ' --debug' + CFLAGS += ' --endian=little' + CFLAGS += ' --cpu=' + CPU + CFLAGS += ' -e' + CFLAGS += ' --fpu=None' + CFLAGS += ' --dlib_config "' + EXEC_PATH + '/arm/INC/c/DLib_Config_Normal.h"' + CFLAGS += ' -Ol' + CFLAGS += ' --use_c++_inline' + + AFLAGS = '' + AFLAGS += ' -s+' + AFLAGS += ' -w+' + AFLAGS += ' -r' + AFLAGS += ' --cpu ' + CPU + AFLAGS += ' --fpu None' + + if BUILD == 'debug': + CFLAGS += ' --debug' + CFLAGS += ' -On' + else: + CFLAGS += ' -Oh' + + LFLAGS = ' --config "board/linker_scripts/link.icf"' + LFLAGS += ' --redirect _Printf=_PrintfTiny' + LFLAGS += ' --redirect _Scanf=_ScanfSmall' + LFLAGS += ' --entry __iar_program_start' + + CXXFLAGS = CFLAGS + + EXEC_PATH = EXEC_PATH + '/arm/bin/' + POST_ACTION = 'ielftool --bin $TARGET rtthread.bin' + +def dist_handle(BSP_ROOT, dist_dir): + import sys + cwd_path = os.getcwd() + sys.path.append(os.path.join(os.path.dirname(BSP_ROOT), 'tools')) + from sdk_dist import dist_do_building + dist_do_building(BSP_ROOT, dist_dir) + + \ No newline at end of file diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvoptx b/Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvoptx new file mode 100644 index 000000000..0f04e4573 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvoptx @@ -0,0 +1,177 @@ + + + + 1.0 + +
### uVision Project, (C) Keil Software
+ + + *.c + *.s*; *.src; *.a* + *.obj; *.o + *.lib + *.txt; *.h; *.inc; *.md + *.plm + *.cpp + 0 + + + + 0 + 0 + + + + rtthread + 0x4 + ARM-ADS + + 12000000 + + 1 + 1 + 0 + 1 + 0 + + + 1 + 65535 + 0 + 0 + 0 + + + 79 + 66 + 8 + .\build\keil\List\ + + + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 0 + + + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + + + 1 + 0 + 1 + + 8 + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 3 + + + + + + + + + + .\flexspi_nor.ini + BIN\CMSIS_AGDI.dll + + + + 0 + CMSIS_AGDI + -X"CMSIS-DAP-v1-MuseLab" -U0700000105dcff343730534243072257 -O974 -S0 -C0 -P00000000 -N00("ARM CoreSight SW-DP") -D00(0BD11477) -L00(0) -TO65554 -TC10000000 -TT10000000 -TP20 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC8000 -FN1 -FF0MIMXRT_QSPIFLASH -FS060000000 -FL02000000 + + + 0 + JL2CM3 + -U30000299 -O78 -S2 -ZTIFSpeedSel5000 -A0 -C0 -JU1 -JI127.0.0.1 -JP0 -RST0 -N00("ARM CoreSight SW-DP") -D00(0BD11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -TB1 -TFE0 -FO15 -FD20000000 -FC8000 -FN1 -FF0MIMXRT105x_QuadSPI_4KB_SEC -FS060000000 -FL0800000 -FP0($$Device:MIMXRT1052CVL5B$arm\MIMXRT105x_QuadSPI_4KB_SEC.FLM) + + + + + 0 + + + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + + 0 + 0 + 0 + + + + + + + + + + + +
diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvprojx b/Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvprojx new file mode 100644 index 000000000..fc37564b1 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/template.uvprojx @@ -0,0 +1,391 @@ + + + + 2.1 + +
### uVision Project, (C) Keil Software
+ + + + rtthread + 0x4 + ARM-ADS + 5060528::V5.06 update 5 (build 528)::ARMCC + 0 + + + MIMXRT1052DVL6B + NXP + NXP.MIMXRT1052_DFP.10.0.1 + http://mcuxpresso.nxp.com/cmsis_pack/repo/ + IRAM(0x20000000,0x020000) IRAM2(0x00000000,0x020000) XRAM(0x20200000,0x040000) CPUTYPE("Cortex-M7") FPU3(DFPU) CLOCK(12000000) ELITTLE + + + + 0 + $$Device:MIMXRT1052DVL6B$fsl_device_registers.h + + + + + + + + + + $$Device:MIMXRT1052DVL6B$MIMXRT1052.xml + 0 + 0 + + + + + + + 0 + 0 + 0 + 0 + 1 + + .\build\keil\Obj\ + rtthread + 1 + 0 + 0 + 1 + 1 + .\build\keil\List\ + 1 + 0 + 0 + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 0 + 0 + + + 0 + 0 + 0 + 0 + + + 1 + 0 + fromelf --bin !L --output rtthread.bin + + 0 + 0 + 0 + 0 + + 0 + + + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 3 + + + 1 + + + SARMCM3.DLL + + DCM.DLL + -pCM7 + SARMCM3.DLL + + TCM.DLL + -pCM7 + + + + 1 + 0 + 0 + 0 + 16 + + + + + 1 + 0 + 0 + 1 + 1 + 4096 + + 1 + BIN\UL2CM3.DLL + + + + + + 0 + + + + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 1 + 1 + 0 + 1 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 0 + 0 + "Cortex-M7" + + 0 + 0 + 0 + 0 + 1 + 1 + 0 + 3 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x20000 + + + 1 + 0x0 + 0x8000 + + + 1 + 0x20200000 + 0x40000 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 1 + 0x0 + 0x0 + + + 0 + 0x20200000 + 0x40000 + + + 0 + 0x0 + 0x0 + + + 0 + 0x0 + 0x0 + + + 0 + 0x20000000 + 0x20000 + + + 0 + 0x0 + 0x20000 + + + + + + 1 + 1 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 1 + 1 + 1 + 1 + 0 + 0 + 0 + + --library_interface=armcc --library_type=standardlib --diag_suppress=66,1296,186 + + + + + + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 4 + + + + + + + + + 0 + 0 + 0 + 0 + 1 + 0 + 0x00000000 + 0x10000000 + + .\board\linker_scripts\link.sct + + + + + 6314 + + + + + + + + + + + + +
diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/SConscript b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/SConscript new file mode 100644 index 000000000..787a0aa93 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/SConscript @@ -0,0 +1,20 @@ +Import('RTT_ROOT') +Import('rtconfig') +from building import * +cwd = GetCurrentDir() +SOURCES = [] +CPPPATH = [cwd] +if GetDepend('BSP_USING_BOOT_IMAGE'): + SOURCES = Glob('*.c') + if rtconfig.CROSS_TOOL == 'keil': + LINKFLAGS = '--keep=*(.boot_hdr.ivt)' + LINKFLAGS += '--keep=*(.boot_hdr.boot_data)' + LINKFLAGS += '--keep=*(.boot_hdr.dcd_data)' + LINKFLAGS += '--keep=*(.boot_hdr.conf)' + else: + SOURCES = Glob('*.c') + LINKFLAGS = '' +else: + LINKFLAGS = '' +group = DefineGroup('xip', src= SOURCES, depend = [''], CPPPATH = CPPPATH, LINKFLAGS = LINKFLAGS) +Return('group') \ No newline at end of file diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.c b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.c new file mode 100644 index 000000000..e4b38b4d1 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.c @@ -0,0 +1,1219 @@ +/* + * Copyright 2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +/** +* @file fsl_flexspi_nor_boot.c +* @brief support to register flexspi image vector table +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-03-22 +*/ + +#include "fsl_flexspi_nor_boot.h" + +#if defined(__CC_ARM) || defined(__GNUC__) + __attribute__((section(".boot_hdr.ivt"))) +#elif defined(__ICCARM__) +#pragma location=".boot_hdr.ivt" +#endif + +const ivt image_vector_table = { + IVT_HEADER, /* IVT Header */ + 0x60002000, /* Image Entry Function */ + IVT_RSVD, /* Reserved = 0 */ + (uint32_t)DCD_ADDRESS, /* Address where DCD information is stored */ + (uint32_t)BOOT_DATA_ADDRESS, /* Address where BOOT Data Structure is stored */ + (uint32_t)&image_vector_table, /* Pointer to IVT Self (absolute address */ + (uint32_t)CSF_ADDRESS, /* Address where CSF file is stored */ + IVT_RSVD /* Reserved = 0 */ +}; + +#if defined(__CC_ARM) || defined(__GNUC__) + __attribute__((section(".boot_hdr.boot_data"))) +#elif defined(__ICCARM__) +#pragma location=".boot_hdr.boot_data" +#endif + +const BOOT_DATA_T boot_data = { + FLASH_BASE, /* boot start location */ + (FLASH_END-FLASH_BASE), /* size */ + PLUGIN_FLAG, /* Plugin flag*/ + 0xFFFFFFFF /* empty - extra data word */ +}; + +#if defined(__CC_ARM) || defined(__GNUC__) + __attribute__((section(".boot_hdr.dcd_data"))) +#elif defined(__ICCARM__) +#pragma location=".boot_hdr.dcd_data" +#endif +//const uint8_t dcd_sdram[1044] = { +///*0000*/ 0xD2, 0x04, 0x14, 0x41, 0xCC, 0x02, 0xF4, 0x04, 0x40, 0x0F, 0xC0, 0x68, 0xFF, 0xFF, 0xFF, 0xFF, +///*0010*/ 0x40, 0x0F, 0xC0, 0x6C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x70, 0xFF, 0xFF, 0xFF, 0xFF, +///*0020*/ 0x40, 0x0F, 0xC0, 0x74, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x78, 0xFF, 0xFF, 0xFF, 0xFF, +///*0030*/ 0x40, 0x0F, 0xC0, 0x7C, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0x0F, 0xC0, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, +///*0040*/ 0x40, 0x0D, 0x80, 0x30, 0x00, 0x00, 0x20, 0x01, 0x40, 0x0D, 0x81, 0x00, 0x00, 0x1D, 0x00, 0x00, +///*0050*/ 0x40, 0x0F, 0xC0, 0x14, 0x00, 0x09, 0x83, 0x40, 0x40, 0x1F, 0x80, 0x14, 0x00, 0x00, 0x00, 0x00, +///*0060*/ 0x40, 0x1F, 0x80, 0x18, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x1C, 0x00, 0x00, 0x00, 0x00, +///*0070*/ 0x40, 0x1F, 0x80, 0x20, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x24, 0x00, 0x00, 0x00, 0x00, +///*0080*/ 0x40, 0x1F, 0x80, 0x28, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x2C, 0x00, 0x00, 0x00, 0x00, +///*0090*/ 0x40, 0x1F, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, +///*00a0*/ 0x40, 0x1F, 0x80, 0x38, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x3C, 0x00, 0x00, 0x00, 0x00, +///*00b0*/ 0x40, 0x1F, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x44, 0x00, 0x00, 0x00, 0x00, +///*00c0*/ 0x40, 0x1F, 0x80, 0x48, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x4C, 0x00, 0x00, 0x00, 0x00, +///*00d0*/ 0x40, 0x1F, 0x80, 0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x54, 0x00, 0x00, 0x00, 0x00, +///*00e0*/ 0x40, 0x1F, 0x80, 0x58, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x5C, 0x00, 0x00, 0x00, 0x00, +///*00f0*/ 0x40, 0x1F, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x64, 0x00, 0x00, 0x00, 0x00, +///*0100*/ 0x40, 0x1F, 0x80, 0x68, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x6C, 0x00, 0x00, 0x00, 0x00, +///*0110*/ 0x40, 0x1F, 0x80, 0x70, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x74, 0x00, 0x00, 0x00, 0x00, +///*0120*/ 0x40, 0x1F, 0x80, 0x78, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x7C, 0x00, 0x00, 0x00, 0x00, +///*0130*/ 0x40, 0x1F, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x84, 0x00, 0x00, 0x00, 0x00, +///*0140*/ 0x40, 0x1F, 0x80, 0x88, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x8C, 0x00, 0x00, 0x00, 0x00, +///*0150*/ 0x40, 0x1F, 0x80, 0x90, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x94, 0x00, 0x00, 0x00, 0x00, +///*0160*/ 0x40, 0x1F, 0x80, 0x98, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0x9C, 0x00, 0x00, 0x00, 0x00, +///*0170*/ 0x40, 0x1F, 0x80, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xA4, 0x00, 0x00, 0x00, 0x00, +///*0180*/ 0x40, 0x1F, 0x80, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x80, 0xAC, 0x00, 0x00, 0x00, 0x00, +///*0190*/ 0x40, 0x1F, 0x80, 0xB0, 0x00, 0x00, 0x00, 0x10, 0x40, 0x1F, 0x80, 0xB4, 0x00, 0x00, 0x00, 0x00, +///*01a0*/ 0x40, 0x1F, 0x80, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1F, 0x82, 0x04, 0x00, 0x00, 0x00, 0xF1, +///*01b0*/ 0x40, 0x1F, 0x82, 0x08, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x0C, 0x00, 0x00, 0x00, 0xF1, +///*01c0*/ 0x40, 0x1F, 0x82, 0x10, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x14, 0x00, 0x00, 0x00, 0xF1, +///*01d0*/ 0x40, 0x1F, 0x82, 0x18, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x1C, 0x00, 0x00, 0x00, 0xF1, +///*01e0*/ 0x40, 0x1F, 0x82, 0x20, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x24, 0x00, 0x00, 0x00, 0xF1, +///*01f0*/ 0x40, 0x1F, 0x82, 0x28, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x2C, 0x00, 0x00, 0x00, 0xF1, +///*0200*/ 0x40, 0x1F, 0x82, 0x30, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x34, 0x00, 0x00, 0x00, 0xF1, +///*0210*/ 0x40, 0x1F, 0x82, 0x38, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x3C, 0x00, 0x00, 0x00, 0xF1, +///*0220*/ 0x40, 0x1F, 0x82, 0x40, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x44, 0x00, 0x00, 0x00, 0xF1, +///*0230*/ 0x40, 0x1F, 0x82, 0x48, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x4C, 0x00, 0x00, 0x00, 0xF1, +///*0240*/ 0x40, 0x1F, 0x82, 0x50, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x54, 0x00, 0x00, 0x00, 0xF1, +///*0250*/ 0x40, 0x1F, 0x82, 0x58, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x5C, 0x00, 0x00, 0x00, 0xF1, +///*0260*/ 0x40, 0x1F, 0x82, 0x60, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x64, 0x00, 0x00, 0x00, 0xF1, +///*0270*/ 0x40, 0x1F, 0x82, 0x68, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x6C, 0x00, 0x00, 0x00, 0xF1, +///*0280*/ 0x40, 0x1F, 0x82, 0x70, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x74, 0x00, 0x00, 0x00, 0xF1, +///*0290*/ 0x40, 0x1F, 0x82, 0x78, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x7C, 0x00, 0x00, 0x00, 0xF1, +///*02a0*/ 0x40, 0x1F, 0x82, 0x80, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x84, 0x00, 0x00, 0x00, 0xF1, +///*02b0*/ 0x40, 0x1F, 0x82, 0x88, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x8C, 0x00, 0x00, 0x00, 0xF1, +///*02c0*/ 0x40, 0x1F, 0x82, 0x90, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x94, 0x00, 0x00, 0x00, 0xF1, +///*02d0*/ 0x40, 0x1F, 0x82, 0x98, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0x9C, 0x00, 0x00, 0x00, 0xF1, +///*02e0*/ 0x40, 0x1F, 0x82, 0xA0, 0x00, 0x00, 0x00, 0xF1, 0x40, 0x1F, 0x82, 0xA4, 0x00, 0x00, 0x00, 0xF1, +///*02f0*/ 0x40, 0x1F, 0x82, 0xA8, 0x00, 0x00, 0x00, 0xF1, 0xCC, 0x00, 0x0C, 0x14, 0x40, 0x2F, 0x00, 0x00, +///*0300*/ 0x00, 0x00, 0x00, 0x02, 0xCC, 0x00, 0x9C, 0x04, 0x40, 0x2F, 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, +///*0310*/ 0x40, 0x2F, 0x00, 0x08, 0x00, 0x03, 0x05, 0x24, 0x40, 0x2F, 0x00, 0x0C, 0x06, 0x03, 0x05, 0x24, +///*0320*/ 0x40, 0x2F, 0x00, 0x10, 0x80, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x14, 0x90, 0x00, 0x00, 0x21, +///*0330*/ 0x40, 0x2F, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x40, 0x2F, 0x00, 0x40, 0x00, 0x00, 0x0B, 0x27, +///*0340*/ 0x40, 0x2F, 0x00, 0x44, 0x00, 0x10, 0x01, 0x00, 0x40, 0x2F, 0x00, 0x48, 0x00, 0x02, 0x02, 0x01, +///*0350*/ 0x40, 0x2F, 0x00, 0x4C, 0x08, 0x19, 0x3D, 0x0E, 0x40, 0x2F, 0x00, 0x74, 0x00, 0x65, 0x29, 0x22, +///*0360*/ 0x40, 0x2F, 0x00, 0x78, 0x00, 0x01, 0x09, 0x20, 0x40, 0x2F, 0x00, 0x7C, 0x50, 0x21, 0x0A, 0x08, +///*0370*/ 0x40, 0x2F, 0x00, 0x80, 0x00, 0x00, 0x00, 0x21, 0x40, 0x2F, 0x00, 0x84, 0x00, 0x88, 0x88, 0x88, +///*0380*/ 0x40, 0x2F, 0x00, 0x94, 0x00, 0x00, 0x00, 0x02, 0x40, 0x2F, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, +///*0390*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0F, +///*03a0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04, +///*03b0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C, +///*03c0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x14, 0x04, +///*03d0*/ 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0C, +///*03e0*/ 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0xCC, 0x00, 0x1C, 0x04, +///*03f0*/ 0x40, 0x2F, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x22, 0x40, 0x2F, 0x00, 0x90, 0x80, 0x00, 0x00, 0x00, +///*0400*/ 0x40, 0x2F, 0x00, 0x9C, 0xA5, 0x5A, 0x00, 0x0A, 0xCF, 0x00, 0x0C, 0x1C, 0x40, 0x2F, 0x00, 0x3C, +///*0410*/ 0x00, 0x00, 0x00, 0x01, +//}; + + + +const uint8_t dcd_sdram[1072] = { + /*0000*/ 0xD2, + 0x04, + 0x30, + 0x41, + 0xCC, + 0x03, + 0xAC, + 0x04, + 0x40, + 0x0F, + 0xC0, + 0x68, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + /*0010*/ 0x40, + 0x0F, + 0xC0, + 0x6C, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x40, + 0x0F, + 0xC0, + 0x70, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + /*0020*/ 0x40, + 0x0F, + 0xC0, + 0x74, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x40, + 0x0F, + 0xC0, + 0x78, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + /*0030*/ 0x40, + 0x0F, + 0xC0, + 0x7C, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0x40, + 0x0F, + 0xC0, + 0x80, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + /*0040*/ 0x40, + 0x0D, + 0x80, + 0x30, + 0x00, + 0x00, + 0x20, + 0x01, + 0x40, + 0x0D, + 0x81, + 0x00, + 0x00, + 0x1D, + 0x00, + 0x00, + /*0050*/ 0x40, + 0x0F, + 0xC0, + 0x14, + 0x00, + 0x01, + 0x0D, + 0x40, + 0x40, + 0x1F, + 0x80, + 0x14, + 0x00, + 0x00, + 0x00, + 0x00, + /*0060*/ 0x40, + 0x1F, + 0x80, + 0x18, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x1C, + 0x00, + 0x00, + 0x00, + 0x00, + /*0070*/ 0x40, + 0x1F, + 0x80, + 0x20, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x24, + 0x00, + 0x00, + 0x00, + 0x00, + /*0080*/ 0x40, + 0x1F, + 0x80, + 0x28, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x2C, + 0x00, + 0x00, + 0x00, + 0x00, + /*0090*/ 0x40, + 0x1F, + 0x80, + 0x30, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x34, + 0x00, + 0x00, + 0x00, + 0x00, + /*00a0*/ 0x40, + 0x1F, + 0x80, + 0x38, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x3C, + 0x00, + 0x00, + 0x00, + 0x00, + /*00b0*/ 0x40, + 0x1F, + 0x80, + 0x40, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x44, + 0x00, + 0x00, + 0x00, + 0x00, + /*00c0*/ 0x40, + 0x1F, + 0x80, + 0x48, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x4C, + 0x00, + 0x00, + 0x00, + 0x00, + /*00d0*/ 0x40, + 0x1F, + 0x80, + 0x50, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x54, + 0x00, + 0x00, + 0x00, + 0x00, + /*00e0*/ 0x40, + 0x1F, + 0x80, + 0x58, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x5C, + 0x00, + 0x00, + 0x00, + 0x00, + /*00f0*/ 0x40, + 0x1F, + 0x80, + 0x60, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x64, + 0x00, + 0x00, + 0x00, + 0x00, + /*0100*/ 0x40, + 0x1F, + 0x80, + 0x68, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x6C, + 0x00, + 0x00, + 0x00, + 0x00, + /*0110*/ 0x40, + 0x1F, + 0x80, + 0x70, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x74, + 0x00, + 0x00, + 0x00, + 0x00, + /*0120*/ 0x40, + 0x1F, + 0x80, + 0x78, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x7C, + 0x00, + 0x00, + 0x00, + 0x00, + /*0130*/ 0x40, + 0x1F, + 0x80, + 0x80, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x84, + 0x00, + 0x00, + 0x00, + 0x00, + /*0140*/ 0x40, + 0x1F, + 0x80, + 0x88, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x8C, + 0x00, + 0x00, + 0x00, + 0x00, + /*0150*/ 0x40, + 0x1F, + 0x80, + 0x90, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x94, + 0x00, + 0x00, + 0x00, + 0x00, + /*0160*/ 0x40, + 0x1F, + 0x80, + 0x98, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0x9C, + 0x00, + 0x00, + 0x00, + 0x00, + /*0170*/ 0x40, + 0x1F, + 0x80, + 0xA0, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0xA4, + 0x00, + 0x00, + 0x00, + 0x00, + /*0180*/ 0x40, + 0x1F, + 0x80, + 0xA8, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x80, + 0xAC, + 0x00, + 0x00, + 0x00, + 0x00, + /*0190*/ 0x40, + 0x1F, + 0x80, + 0xB0, + 0x00, + 0x00, + 0x00, + 0x10, + 0x40, + 0x1F, + 0x80, + 0xB4, + 0x00, + 0x00, + 0x00, + 0x00, + /*01a0*/ 0x40, + 0x1F, + 0x80, + 0xB8, + 0x00, + 0x00, + 0x00, + 0x00, + 0x40, + 0x1F, + 0x82, + 0x04, + 0x00, + 0x01, + 0x10, + 0xF9, + /*01b0*/ 0x40, + 0x1F, + 0x82, + 0x08, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x0C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*01c0*/ 0x40, + 0x1F, + 0x82, + 0x10, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x14, + 0x00, + 0x01, + 0x10, + 0xF9, + /*01d0*/ 0x40, + 0x1F, + 0x82, + 0x18, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x1C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*01e0*/ 0x40, + 0x1F, + 0x82, + 0x20, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x24, + 0x00, + 0x01, + 0x10, + 0xF9, + /*01f0*/ 0x40, + 0x1F, + 0x82, + 0x28, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x2C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0200*/ 0x40, + 0x1F, + 0x82, + 0x30, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x34, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0210*/ 0x40, + 0x1F, + 0x82, + 0x38, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x3C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0220*/ 0x40, + 0x1F, + 0x82, + 0x40, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x44, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0230*/ 0x40, + 0x1F, + 0x82, + 0x48, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x4C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0240*/ 0x40, + 0x1F, + 0x82, + 0x50, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x54, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0250*/ 0x40, + 0x1F, + 0x82, + 0x58, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x5C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0260*/ 0x40, + 0x1F, + 0x82, + 0x60, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x64, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0270*/ 0x40, + 0x1F, + 0x82, + 0x68, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x6C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0280*/ 0x40, + 0x1F, + 0x82, + 0x70, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x74, + 0x00, + 0x01, + 0x10, + 0xF9, + /*0290*/ 0x40, + 0x1F, + 0x82, + 0x78, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x7C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*02a0*/ 0x40, + 0x1F, + 0x82, + 0x80, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x84, + 0x00, + 0x01, + 0x10, + 0xF9, + /*02b0*/ 0x40, + 0x1F, + 0x82, + 0x88, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x8C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*02c0*/ 0x40, + 0x1F, + 0x82, + 0x90, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x94, + 0x00, + 0x01, + 0x10, + 0xF9, + /*02d0*/ 0x40, + 0x1F, + 0x82, + 0x98, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0x9C, + 0x00, + 0x01, + 0x10, + 0xF9, + /*02e0*/ 0x40, + 0x1F, + 0x82, + 0xA0, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x1F, + 0x82, + 0xA4, + 0x00, + 0x01, + 0x10, + 0xF9, + /*02f0*/ 0x40, + 0x1F, + 0x82, + 0xA8, + 0x00, + 0x01, + 0x10, + 0xF9, + 0x40, + 0x2F, + 0x00, + 0x00, + 0x10, + 0x00, + 0x00, + 0x04, + /*0300*/ 0x40, + 0x2F, + 0x00, + 0x08, + 0x00, + 0x03, + 0x05, + 0x24, + 0x40, + 0x2F, + 0x00, + 0x0C, + 0x06, + 0x03, + 0x05, + 0x24, + /*0310*/ 0x40, + 0x2F, + 0x00, + 0x10, + 0x80, + 0x00, + 0x00, + 0x1B, + 0x40, + 0x2F, + 0x00, + 0x14, + 0x82, + 0x00, + 0x00, + 0x1B, + /*0320*/ 0x40, + 0x2F, + 0x00, + 0x18, + 0x84, + 0x00, + 0x00, + 0x1B, + 0x40, + 0x2F, + 0x00, + 0x1C, + 0x86, + 0x00, + 0x00, + 0x1B, + /*0330*/ 0x40, + 0x2F, + 0x00, + 0x20, + 0x90, + 0x00, + 0x00, + 0x21, + 0x40, + 0x2F, + 0x00, + 0x24, + 0xA0, + 0x00, + 0x00, + 0x19, + /*0340*/ 0x40, + 0x2F, + 0x00, + 0x28, + 0xA8, + 0x00, + 0x00, + 0x17, + 0x40, + 0x2F, + 0x00, + 0x2C, + 0xA9, + 0x00, + 0x00, + 0x1B, + /*0350*/ 0x40, + 0x2F, + 0x00, + 0x30, + 0x00, + 0x00, + 0x00, + 0x21, + 0x40, + 0x2F, + 0x00, + 0x04, + 0x00, + 0x00, + 0x79, + 0xA8, + /*0360*/ 0x40, + 0x2F, + 0x00, + 0x40, + 0x00, + 0x00, + 0x0F, + 0x31, + 0x40, + 0x2F, + 0x00, + 0x44, + 0x00, + 0x65, + 0x29, + 0x22, + /*0370*/ 0x40, + 0x2F, + 0x00, + 0x48, + 0x00, + 0x01, + 0x09, + 0x20, + 0x40, + 0x2F, + 0x00, + 0x4C, + 0x50, + 0x21, + 0x0A, + 0x08, + /*0380*/ 0x40, + 0x2F, + 0x00, + 0x80, + 0x00, + 0x00, + 0x00, + 0x21, + 0x40, + 0x2F, + 0x00, + 0x84, + 0x00, + 0x88, + 0x88, + 0x88, + /*0390*/ 0x40, + 0x2F, + 0x00, + 0x94, + 0x00, + 0x00, + 0x00, + 0x02, + 0x40, + 0x2F, + 0x00, + 0x98, + 0x00, + 0x00, + 0x00, + 0x00, + /*03a0*/ 0x40, + 0x2F, + 0x00, + 0x90, + 0x80, + 0x00, + 0x00, + 0x00, + 0x40, + 0x2F, + 0x00, + 0x9C, + 0xA5, + 0x5A, + 0x00, + 0x0F, + /*03b0*/ 0xCF, + 0x00, + 0x0C, + 0x1C, + 0x40, + 0x2F, + 0x00, + 0x3C, + 0x00, + 0x00, + 0x00, + 0x01, + 0xCC, + 0x00, + 0x14, + 0x04, + /*03c0*/ 0x40, + 0x2F, + 0x00, + 0x90, + 0x80, + 0x00, + 0x00, + 0x00, + 0x40, + 0x2F, + 0x00, + 0x9C, + 0xA5, + 0x5A, + 0x00, + 0x0C, + /*03d0*/ 0xCF, + 0x00, + 0x0C, + 0x1C, + 0x40, + 0x2F, + 0x00, + 0x3C, + 0x00, + 0x00, + 0x00, + 0x01, + 0xCC, + 0x00, + 0x14, + 0x04, + /*03e0*/ 0x40, + 0x2F, + 0x00, + 0x90, + 0x80, + 0x00, + 0x00, + 0x00, + 0x40, + 0x2F, + 0x00, + 0x9C, + 0xA5, + 0x5A, + 0x00, + 0x0C, + /*03f0*/ 0xCF, + 0x00, + 0x0C, + 0x1C, + 0x40, + 0x2F, + 0x00, + 0x3C, + 0x00, + 0x00, + 0x00, + 0x01, + 0xCC, + 0x00, + 0x1C, + 0x04, + /*0400*/ 0x40, + 0x2F, + 0x00, + 0xA0, + 0x00, + 0x00, + 0x00, + 0x33, + 0x40, + 0x2F, + 0x00, + 0x90, + 0x80, + 0x00, + 0x00, + 0x00, + /*0410*/ 0x40, + 0x2F, + 0x00, + 0x9C, + 0xA5, + 0x5A, + 0x00, + 0x0A, + 0xCF, + 0x00, + 0x0C, + 0x1C, + 0x40, + 0x2F, + 0x00, + 0x3C, + /*0420*/ 0x00, + 0x00, + 0x00, + 0x01, + 0xCC, + 0x00, + 0x0C, + 0x04, + 0x40, + 0x2F, + 0x00, + 0x4C, + 0x50, + 0x07, + 0x0A, + 0x09, +}; diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.h new file mode 100644 index 000000000..56b568b8e --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_boot.h @@ -0,0 +1,123 @@ +/* + * Copyright 2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +/** +* @file fsl_flexspi_nor_boot.h +* @brief support to register flexspi image vector table +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-03-22 +*/ + +#ifndef _QUADSPI_BOOT_H_ +#define _QUADSPI_BOOT_H_ + +#include + +/************************************* + * IVT Data + *************************************/ +typedef struct _ivt_ { + /** @ref hdr with tag #HAB_TAG_IVT, length and HAB version fields + * (see @ref data) + */ + uint32_t hdr; + /** Absolute address of the first instruction to execute from the + * image + */ + uint32_t entry; + /** Reserved in this version of HAB: should be NULL. */ + uint32_t reserved1; + /** Absolute address of the image DCD: may be NULL. */ + uint32_t dcd; + /** Absolute address of the Boot Data: may be NULL, but not interpreted + * any further by HAB + */ + uint32_t boot_data; + /** Absolute address of the IVT.*/ + uint32_t self; + /** Absolute address of the image CSF.*/ + uint32_t csf; + /** Reserved in this version of HAB: should be zero. */ + uint32_t reserved2; +} ivt; + +#define IVT_MAJOR_VERSION 0x4 +#define IVT_MAJOR_VERSION_SHIFT 0x4 +#define IVT_MAJOR_VERSION_MASK 0xF +#define IVT_MINOR_VERSION 0x1 +#define IVT_MINOR_VERSION_SHIFT 0x0 +#define IVT_MINOR_VERSION_MASK 0xF + +#define IVT_VERSION(major, minor) \ + ((((major) & IVT_MAJOR_VERSION_MASK) << IVT_MAJOR_VERSION_SHIFT) | \ + (((minor) & IVT_MINOR_VERSION_MASK) << IVT_MINOR_VERSION_SHIFT)) + +#define IVT_TAG_HEADER (0xD1) /**< Image Vector Table */ +#define IVT_SIZE 0x2000 +#define IVT_PAR IVT_VERSION(IVT_MAJOR_VERSION, IVT_MINOR_VERSION) + +#define IVT_HEADER (IVT_TAG_HEADER | (IVT_SIZE << 8) | (IVT_PAR << 24)) +#define IVT_RSVD (uint32_t)(0x00000000) + + +/************************************* + * Boot Data + *************************************/ +typedef struct _boot_data_ { + uint32_t start; /* boot start location */ + uint32_t size; /* size */ + uint32_t plugin; /* plugin flag - 1 if downloaded application is plugin */ + uint32_t placeholder; /* placehoder to make even 0x10 size */ +}BOOT_DATA_T; + + +/************************************* + * DCD Data + *************************************/ +#define DCD_TAG_HEADER (0xD2) +#define DCD_TAG_HEADER_SHIFT (24) +#define DCD_VERSION (0x40) +#define DCD_ARRAY_SIZE 1 + +#define FLASH_BASE 0x60000000 +#define FLASH_END 0x7F7FFFFF +#define SCLK 1 + +#define DCD_ADDRESS dcd_sdram +#define BOOT_DATA_ADDRESS &boot_data +#define CSF_ADDRESS 0 +#define PLUGIN_FLAG (uint32_t)0 + +/* External Variables */ +//extern const uint8_t dcd_sdram[1044]; +extern const uint8_t dcd_sdram[1072]; +extern const BOOT_DATA_T boot_data; + +#endif diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.c b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.c new file mode 100644 index 000000000..9fd83eef8 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.c @@ -0,0 +1,88 @@ +/* + * Copyright 2017 NXP + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +/** +* @file fsl_flexspi_nor_flash.c +* @brief support to define flexspi flash config +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-03-22 +*/ + +#include "fsl_flexspi_nor_flash.h" + +/******************************************************************************* + * Code + ******************************************************************************/ +#if defined(__CC_ARM) || defined(__GNUC__) + __attribute__((section(".boot_hdr.conf"))) +#elif defined(__ICCARM__) +#pragma location=".boot_hdr.conf" +#endif + +const flexspi_nor_config_t Qspiflash_config = +{ + .memConfig = + { + .tag = FLEXSPI_CFG_BLK_TAG, + .version = FLEXSPI_CFG_BLK_VERSION, + .readSampleClkSrc = kFlexSPIReadSampleClk_LoopbackInternally, + .csHoldTime = 3u, + .csSetupTime = 3u, + .deviceModeCfgEnable = true, + .deviceModeType = 1,//Quad Enable command + .deviceModeSeq.seqNum = 1, + .deviceModeSeq.seqId = 4, + .deviceModeArg = 0x000200,//Set QE + .deviceType = kFlexSpiDeviceType_SerialNOR, + .sflashPadType = kSerialFlash_4Pads, + .serialClkFreq = kFlexSpiSerialClk_60MHz,//80MHz for Winbond, 100MHz for GD, 133MHz for ISSI + .sflashA1Size = 16u * 1024u * 1024u,//4MBytes + .dataValidTime = {16u, 16u}, + .lookupTable = + { +// //Fast Read Sequence +// [0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x0B, RADDR_SDR, FLEXSPI_1PAD, 0x18), +// [1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_1PAD, 0x08, READ_SDR, FLEXSPI_1PAD, 0x08), +// [2] = FLEXSPI_LUT_SEQ(JMP_ON_CS, 0, 0, 0, 0, 0), + //Quad Input/output read sequence + [0] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0xEB, RADDR_SDR, FLEXSPI_4PAD, 0x18), + [1] = FLEXSPI_LUT_SEQ(DUMMY_SDR, FLEXSPI_4PAD, 0x06, READ_SDR, FLEXSPI_4PAD, 0x04), + [2] = FLEXSPI_LUT_SEQ(0, 0, 0, 0, 0, 0), + //Read Status + [1*4] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x05, READ_SDR, FLEXSPI_1PAD, 0x04), + //Write Enable + [3*4] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x06, STOP, 0, 0), + //Write status + [4*4] = FLEXSPI_LUT_SEQ(CMD_SDR, FLEXSPI_1PAD, 0x01, WRITE_SDR, FLEXSPI_1PAD, 0x2), + }, + }, + .pageSize = 256u, + .sectorSize = 4u * 1024u, +}; diff --git a/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.h b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.h new file mode 100644 index 000000000..940baf8b5 --- /dev/null +++ b/Ubiquitous/RT_Thread/aiit_board/xidatong/xip/fsl_flexspi_nor_flash.h @@ -0,0 +1,303 @@ +/* + * Copyright (c) 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * + * Redistribution and use in source and binary forms, with or without + * modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this + * list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. + */ + +/** +* @file fsl_flexspi_nor_flash.h +* @brief support to define flexspi flash config +* @version 2.0 +* @author AIIT XUOS Lab +* @date 2022-03-22 +*/ + +#ifndef __FLEXSPI_NOR_FLASH_H__ +#define __FLEXSPI_NOR_FLASH_H__ + +#include +#include +#include "fsl_common.h" + +/* FLEXSPI memory config block related defintions */ +#define FLEXSPI_CFG_BLK_TAG (0x42464346UL) // ascii "FCFB" Big Endian +#define FLEXSPI_CFG_BLK_VERSION (0x56010400UL) // V1.4.0 +#define FLEXSPI_CFG_BLK_SIZE (512) + +/* FLEXSPI Feature related definitions */ +#define FLEXSPI_FEATURE_HAS_PARALLEL_MODE 1 + +/* Lookup table related defintions */ +#define CMD_INDEX_READ 0 +#define CMD_INDEX_READSTATUS 1 +#define CMD_INDEX_WRITEENABLE 2 +#define CMD_INDEX_WRITE 4 + +#define CMD_LUT_SEQ_IDX_READ 0 +#define CMD_LUT_SEQ_IDX_READSTATUS 1 +#define CMD_LUT_SEQ_IDX_WRITEENABLE 3 +#define CMD_LUT_SEQ_IDX_WRITE 9 + +#define CMD_SDR 0x01 +#define CMD_DDR 0x21 +#define RADDR_SDR 0x02 +#define RADDR_DDR 0x22 +#define CADDR_SDR 0x03 +#define CADDR_DDR 0x23 +#define MODE1_SDR 0x04 +#define MODE1_DDR 0x24 +#define MODE2_SDR 0x05 +#define MODE2_DDR 0x25 +#define MODE4_SDR 0x06 +#define MODE4_DDR 0x26 +#define MODE8_SDR 0x07 +#define MODE8_DDR 0x27 +#define WRITE_SDR 0x08 +#define WRITE_DDR 0x28 +#define READ_SDR 0x09 +#define READ_DDR 0x29 +#define LEARN_SDR 0x0A +#define LEARN_DDR 0x2A +#define DATSZ_SDR 0x0B +#define DATSZ_DDR 0x2B +#define DUMMY_SDR 0x0C +#define DUMMY_DDR 0x2C +#define DUMMY_RWDS_SDR 0x0D +#define DUMMY_RWDS_DDR 0x2D +#define JMP_ON_CS 0x1F +#define STOP 0 + +#define FLEXSPI_1PAD 0 +#define FLEXSPI_2PAD 1 +#define FLEXSPI_4PAD 2 +#define FLEXSPI_8PAD 3 + +#define FLEXSPI_LUT_SEQ(cmd0, pad0, op0, cmd1, pad1, op1) \ + (FLEXSPI_LUT_OPERAND0(op0) | FLEXSPI_LUT_NUM_PADS0(pad0) | FLEXSPI_LUT_OPCODE0(cmd0) | FLEXSPI_LUT_OPERAND1(op1) | \ + FLEXSPI_LUT_NUM_PADS1(pad1) | FLEXSPI_LUT_OPCODE1(cmd1)) + +//!@brief Definitions for FlexSPI Serial Clock Frequency +typedef enum _FlexSpiSerialClockFreq +{ + kFlexSpiSerialClk_30MHz = 1, + kFlexSpiSerialClk_50MHz = 2, + kFlexSpiSerialClk_60MHz = 3, + kFlexSpiSerialClk_75MHz = 4, + kFlexSpiSerialClk_80MHz = 5, + kFlexSpiSerialClk_100MHz = 6, + kFlexSpiSerialClk_133MHz = 7, + kFlexSpiSerialClk_166MHz = 8, + kFlexSpiSerialClk_200MHz = 9, +} flexspi_serial_clk_freq_t; + +//!@brief FlexSPI clock configuration type +enum +{ + kFlexSpiClk_SDR, //!< Clock configure for SDR mode + kFlexSpiClk_DDR, //!< Clock configurat for DDR mode +}; + +//!@brief FlexSPI Read Sample Clock Source definition +typedef enum _FlashReadSampleClkSource +{ + kFlexSPIReadSampleClk_LoopbackInternally = 0, + kFlexSPIReadSampleClk_LoopbackFromDqsPad = 1, + kFlexSPIReadSampleClk_LoopbackFromSckPad = 2, + kFlexSPIReadSampleClk_ExternalInputFromDqsPad = 3, +} flexspi_read_sample_clk_t; + + +//!@brief Misc feature bit definitions +enum +{ + kFlexSpiMiscOffset_DiffClkEnable = 0, //!< Bit for Differential clock enable + kFlexSpiMiscOffset_Ck2Enable = 1, //!< Bit for CK2 enable + kFlexSpiMiscOffset_ParallelEnable = 2, //!< Bit for Parallel mode enable + kFlexSpiMiscOffset_WordAddressableEnable = 3, //!< Bit for Word Addressable enable + kFlexSpiMiscOffset_SafeConfigFreqEnable = 4, //!< Bit for Safe Configuration Frequency enable + kFlexSpiMiscOffset_PadSettingOverrideEnable = 5, //!< Bit for Pad setting override enable + kFlexSpiMiscOffset_DdrModeEnable = 6, //!< Bit for DDR clock confiuration indication. +}; + +//!@brief Flash Type Definition +enum +{ + kFlexSpiDeviceType_SerialNOR = 1, //!< Flash devices are Serial NOR + kFlexSpiDeviceType_SerialNAND = 2, //!< Flash devices are Serial NAND + kFlexSpiDeviceType_SerialRAM = 3, //!< Flash devices are Serial RAM/HyperFLASH + kFlexSpiDeviceType_MCP_NOR_NAND = 0x12, //!< Flash device is MCP device, A1 is Serial NOR, A2 is Serial NAND + kFlexSpiDeviceType_MCP_NOR_RAM = 0x13, //!< Flash deivce is MCP device, A1 is Serial NOR, A2 is Serial RAMs +}; + +//!@brief Flash Pad Definitions +enum +{ + kSerialFlash_1Pad = 1, + kSerialFlash_2Pads = 2, + kSerialFlash_4Pads = 4, + kSerialFlash_8Pads = 8, +}; + +//!@brief FlexSPI LUT Sequence structure +typedef struct _lut_sequence +{ + uint8_t seqNum; //!< Sequence Number, valid number: 1-16 + uint8_t seqId; //!< Sequence Index, valid number: 0-15 + uint16_t reserved; +} flexspi_lut_seq_t; + +//!@brief Flash Configuration Command Type +enum +{ + kDeviceConfigCmdType_Generic, //!< Generic command, for example: configure dummy cycles, drive strength, etc + kDeviceConfigCmdType_QuadEnable, //!< Quad Enable command + kDeviceConfigCmdType_Spi2Xpi, //!< Switch from SPI to DPI/QPI/OPI mode + kDeviceConfigCmdType_Xpi2Spi, //!< Switch from DPI/QPI/OPI to SPI mode + kDeviceConfigCmdType_Spi2NoCmd, //!< Switch to 0-4-4/0-8-8 mode + kDeviceConfigCmdType_Reset, //!< Reset device command +}; + +//!@brief FlexSPI Memory Configuration Block +typedef struct _FlexSPIConfig +{ + uint32_t tag; //!< [0x000-0x003] Tag, fixed value 0x42464346UL + uint32_t version; //!< [0x004-0x007] Version,[31:24] -'V', [23:16] - Major, [15:8] - Minor, [7:0] - bugfix + uint32_t reserved0; //!< [0x008-0x00b] Reserved for future use + uint8_t readSampleClkSrc; //!< [0x00c-0x00c] Read Sample Clock Source, valid value: 0/1/3 + uint8_t csHoldTime; //!< [0x00d-0x00d] CS hold time, default value: 3 + uint8_t csSetupTime; //!< [0x00e-0x00e] CS setup time, default value: 3 + uint8_t columnAddressWidth; //!< [0x00f-0x00f] Column Address with, for HyperBus protocol, it is fixed to 3, For + //! Serial NAND, need to refer to datasheet + uint8_t deviceModeCfgEnable; //!< [0x010-0x010] Device Mode Configure enable flag, 1 - Enable, 0 - Disable + uint8_t deviceModeType; //!< [0x011-0x011] Specify the configuration command type:Quad Enable, DPI/QPI/OPI switch, + //! Generic configuration, etc. + uint16_t waitTimeCfgCommands; //!< [0x012-0x013] Wait time for all configuration commands, unit: 100us, Used for + //! DPI/QPI/OPI switch or reset command + flexspi_lut_seq_t deviceModeSeq; //!< [0x014-0x017] Device mode sequence info, [7:0] - LUT sequence id, [15:8] - LUt + //! sequence number, [31:16] Reserved + uint32_t deviceModeArg; //!< [0x018-0x01b] Argument/Parameter for device configuration + uint8_t configCmdEnable; //!< [0x01c-0x01c] Configure command Enable Flag, 1 - Enable, 0 - Disable + uint8_t configModeType[3]; //!< [0x01d-0x01f] Configure Mode Type, similar as deviceModeTpe + flexspi_lut_seq_t + configCmdSeqs[3]; //!< [0x020-0x02b] Sequence info for Device Configuration command, similar as deviceModeSeq + uint32_t reserved1; //!< [0x02c-0x02f] Reserved for future use + uint32_t configCmdArgs[3]; //!< [0x030-0x03b] Arguments/Parameters for device Configuration commands + uint32_t reserved2; //!< [0x03c-0x03f] Reserved for future use + uint32_t controllerMiscOption; //!< [0x040-0x043] Controller Misc Options, see Misc feature bit definitions for more + //! details + uint8_t deviceType; //!< [0x044-0x044] Device Type: See Flash Type Definition for more details + uint8_t sflashPadType; //!< [0x045-0x045] Serial Flash Pad Type: 1 - Single, 2 - Dual, 4 - Quad, 8 - Octal + uint8_t serialClkFreq; //!< [0x046-0x046] Serial Flash Frequencey, device specific definitions, See System Boot + //! Chapter for more details + uint8_t lutCustomSeqEnable; //!< [0x047-0x047] LUT customization Enable, it is required if the program/erase cannot + //! be done using 1 LUT sequence, currently, only applicable to HyperFLASH + uint32_t reserved3[2]; //!< [0x048-0x04f] Reserved for future use + uint32_t sflashA1Size; //!< [0x050-0x053] Size of Flash connected to A1 + uint32_t sflashA2Size; //!< [0x054-0x057] Size of Flash connected to A2 + uint32_t sflashB1Size; //!< [0x058-0x05b] Size of Flash connected to B1 + uint32_t sflashB2Size; //!< [0x05c-0x05f] Size of Flash connected to B2 + uint32_t csPadSettingOverride; //!< [0x060-0x063] CS pad setting override value + uint32_t sclkPadSettingOverride; //!< [0x064-0x067] SCK pad setting override value + uint32_t dataPadSettingOverride; //!< [0x068-0x06b] data pad setting override value + uint32_t dqsPadSettingOverride; //!< [0x06c-0x06f] DQS pad setting override value + uint32_t timeoutInMs; //!< [0x070-0x073] Timeout threshold for read status command + uint32_t commandInterval; //!< [0x074-0x077] CS deselect interval between two commands + uint16_t dataValidTime[2]; //!< [0x078-0x07b] CLK edge to data valid time for PORT A and PORT B, in terms of 0.1ns + uint16_t busyOffset; //!< [0x07c-0x07d] Busy offset, valid value: 0-31 + uint16_t busyBitPolarity; //!< [0x07e-0x07f] Busy flag polarity, 0 - busy flag is 1 when flash device is busy, 1 - + //! busy flag is 0 when flash device is busy + uint32_t lookupTable[64]; //!< [0x080-0x17f] Lookup table holds Flash command sequences + flexspi_lut_seq_t lutCustomSeq[12]; //!< [0x180-0x1af] Customizable LUT Sequences + uint32_t reserved4[4]; //!< [0x1b0-0x1bf] Reserved for future use +} flexspi_mem_config_t; + +/* */ +#define NOR_CMD_INDEX_READ CMD_INDEX_READ //!< 0 +#define NOR_CMD_INDEX_READSTATUS CMD_INDEX_READSTATUS //!< 1 +#define NOR_CMD_INDEX_WRITEENABLE CMD_INDEX_WRITEENABLE //!< 2 +#define NOR_CMD_INDEX_ERASESECTOR 3 //!< 3 +#define NOR_CMD_INDEX_PAGEPROGRAM CMD_INDEX_WRITE //!< 4 +#define NOR_CMD_INDEX_CHIPERASE 5 //!< 5 +#define NOR_CMD_INDEX_DUMMY 6 //!< 6 +#define NOR_CMD_INDEX_ERASEBLOCK 7 //!< 7 + +#define NOR_CMD_LUT_SEQ_IDX_READ CMD_LUT_SEQ_IDX_READ //!< 0 READ LUT sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS \ + CMD_LUT_SEQ_IDX_READSTATUS //!< 1 Read Status LUT sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_READSTATUS_XPI \ + 2 //!< 2 Read status DPI/QPI/OPI sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE \ + CMD_LUT_SEQ_IDX_WRITEENABLE //!< 3 Write Enable sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_WRITEENABLE_XPI \ + 4 //!< 4 Write Enable DPI/QPI/OPI sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_ERASESECTOR 5 //!< 5 Erase Sector sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_ERASEBLOCK 8 //!< 8 Erase Block sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_PAGEPROGRAM \ + CMD_LUT_SEQ_IDX_WRITE //!< 9 Program sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_CHIPERASE 11 //!< 11 Chip Erase sequence in lookupTable id stored in config block +#define NOR_CMD_LUT_SEQ_IDX_READ_SFDP 13 //!< 13 Read SFDP sequence in lookupTable id stored in config block +#define NOR_CMD_LUT_SEQ_IDX_RESTORE_NOCMD \ + 14 //!< 14 Restore 0-4-4/0-8-8 mode sequence id in lookupTable stored in config block +#define NOR_CMD_LUT_SEQ_IDX_EXIT_NOCMD \ + 15 //!< 15 Exit 0-4-4/0-8-8 mode sequence id in lookupTable stored in config blobk + + +/* + * Serial NOR configuration block + */ +typedef struct _flexspi_nor_config +{ + flexspi_mem_config_t memConfig; //!< Common memory configuration info via FlexSPI + uint32_t pageSize; //!< Page size of Serial NOR + uint32_t sectorSize; //!< Sector size of Serial NOR + uint8_t ipcmdSerialClkFreq; //!< Clock frequency for IP command + uint8_t isUniformBlockSize; //!< Sector/Block size is the same + uint8_t reserved0[2]; //!< Reserved for future use + uint8_t serialNorType; //!< Serial NOR Flash type: 0/1/2/3 + uint8_t needExitNoCmdMode; //!< Need to exit NoCmd mode before other IP command + uint8_t halfClkForNonReadCmd; //!< Half the Serial Clock for non-read command: true/false + uint8_t needRestoreNoCmdMode; //!< Need to Restore NoCmd mode after IP commmand execution + uint32_t blockSize; //!< Block size + uint32_t reserve2[11]; //!< Reserved for future use +} flexspi_nor_config_t; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif // __FLEXSPI_NOR_FLASH_H__ From 59dbe7058be460f5df318b2c975f1921fdb42a4a Mon Sep 17 00:00:00 2001 From: Liu_Weichao Date: Thu, 24 Mar 2022 15:17:47 +0800 Subject: [PATCH 3/5] feat support ch438 extuart function for xidatong board --- .../third_party_driver/gpio/connect_gpio.c | 3 + .../third_party_driver/ch438/connect_ch438.c | 198 +++++++++++------- .../third_party_driver/gpio/connect_gpio.c | 19 +- .../include/connect_ch438.h | 6 +- 4 files changed, 141 insertions(+), 85 deletions(-) diff --git a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c index 2bbb15f76..dd6697921 100755 --- a/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c +++ b/Ubiquitous/XiZi/board/ok1052-c/third_party_driver/gpio/connect_gpio.c @@ -581,6 +581,9 @@ static __inline void PinIrqHdr(uint32_t index_offset, uint8_t pin_start, GPIO_Ty if (isr_status & (1 << i)) { GPIO_PortClearInterruptFlags(gpio, (1 << i)); + + __DSB(); + pin = index_offset + i; if (pin_irq_hdr_tab[pin].hdr) { pin_irq_hdr_tab[pin].hdr(pin_irq_hdr_tab[pin].args); diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ch438/connect_ch438.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ch438/connect_ch438.c index abead660c..500a54fa7 100644 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ch438/connect_ch438.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ch438/connect_ch438.c @@ -611,7 +611,7 @@ void WriteCH438Data(uint8 addr, uint8 dat) ********************************************************************************************************/ void WriteCH438Block(uint8 maddr, uint8 mlen, uint8 *mbuf) { - while (mlen--) { + while (mlen--) { WriteCH438Data(maddr, *mbuf++); } } @@ -742,7 +742,7 @@ static void Timeout438Proc(void *parameter) } } -void Ch438PortInit( uint8 ext_uart_no,uint32 BaudRate ) +void Ch438PortInit(uint8 ext_uart_no, uint32 BaudRate ) { uint32 div; uint8 DLL,DLM,dlab; @@ -767,7 +767,8 @@ void Ch438PortInit( uint8 ext_uart_no,uint32 BaudRate ) REG_IIR_ADDR = offset_addr[ext_uart_no] | REG_IIR0_ADDR; WriteCH438Data(REG_IER_ADDR, BIT_IER_RESET); /* reset the uart */ - MdelayKTask(50); + //MdelayKTask(50); + ImxrtUdelay(50000); dlab = ReadCH438Data(REG_IER_ADDR); dlab &= 0xDF; @@ -818,7 +819,8 @@ void CH438PortInitParityCheck(uint8 ext_uart_no, uint32 BaudRate) REG_IIR_ADDR = offset_addr[ext_uart_no] | REG_IIR0_ADDR; WriteCH438Data(REG_IER_ADDR, BIT_IER_RESET); /* reset the uart */ - MdelayKTask(50); + //MdelayKTask(50); + ImxrtUdelay(50000); dlab = ReadCH438Data(REG_IER_ADDR); dlab &= 0xDF; @@ -896,14 +898,12 @@ static uint32 ImxrtCh438Init(struct SerialDriver *serial_drv, struct SerialCfgP } /* config NRD pin as output*/ - KPrintf("####TEST CH438_NRD_PIN %u start####\n", CH438_NRD_PIN); pin_cfg.pin = CH438_NRD_PIN; ret = BusDrvConfigure(ch438_pin->owner_driver, &configure_info); if (ret != EOK) { KPrintf("config NRD pin %d failed!\n", CH438_NRD_PIN); return ERROR; } - KPrintf("####TEST CH438_NRD_PIN %u done####\n", CH438_NRD_PIN); /* config ALE pin as output*/ pin_cfg.pin = CH438_ALE_PIN; @@ -1027,7 +1027,7 @@ static uint32 ImxrtCh438ReadData(void *dev, struct BusBlockReadParam *read_param case INT_THR_EMPTY: /* THR EMPTY INTERRUPT*/ break; case INT_RCV_OVERTIME: /* RECV OVERTIME INTERRUPT*/ - case INT_RCV_SUCCESS: /* RECV INTERRUPT SUCCESSFULLY*/ + case INT_RCV_SUCCESS: /* RECV INTERRUPT SUCCESSFULLY*/ rcv_num = Ch438UartRcv(dev_param->ext_uart_no, (uint8 *)read_param->buffer, read_param->size); read_param->read_length = rcv_num; break; @@ -1056,14 +1056,14 @@ static const struct SerialDevDone dev_done = static void Ch438InitDefault(struct SerialDriver *serial_drv) { - struct PinParam PinCfg; + struct PinParam pin_cfg; BusType ch438_pin; struct BusConfigureInfo configure_info; int ret = 0; configure_info.configure_cmd = OPE_CFG; - configure_info.private_data = (void *)&PinCfg; + configure_info.private_data = (void *)&pin_cfg; ch438_sem = KSemaphoreCreate(0); if (ch438_sem < 0) { @@ -1073,72 +1073,43 @@ static void Ch438InitDefault(struct SerialDriver *serial_drv) ch438_pin = PinBusInitGet(); - PinCfg.cmd = GPIO_CONFIG_MODE; - PinCfg.pin = CH438_INT_PIN; - PinCfg.mode = GPIO_CFG_INPUT_PULLUP; + pin_cfg.cmd = GPIO_CONFIG_MODE; + pin_cfg.pin = CH438_INT_PIN; + pin_cfg.mode = GPIO_CFG_INPUT_PULLUP; ret = BusDrvConfigure(ch438_pin->owner_driver, &configure_info); if (ret != EOK) { KPrintf("config BSP_CH438_INT_PIN pin %d failed!\n", CH438_INT_PIN); return; } - PinCfg.cmd = GPIO_IRQ_REGISTER; - PinCfg.pin = CH438_INT_PIN; - PinCfg.irq_set.irq_mode = GPIO_IRQ_EDGE_FALLING; - PinCfg.irq_set.hdr = Ch438Irq; - PinCfg.irq_set.args = NONE; + pin_cfg.cmd = GPIO_IRQ_REGISTER; + pin_cfg.pin = CH438_INT_PIN; + pin_cfg.irq_set.irq_mode = GPIO_IRQ_EDGE_FALLING; + pin_cfg.irq_set.hdr = Ch438Irq; + pin_cfg.irq_set.args = NONE; ret = BusDrvConfigure(ch438_pin->owner_driver, &configure_info); if (ret != EOK) { - KPrintf("config BSP_CH438_INT_PIN %d failed!\n", CH438_INT_PIN); + KPrintf("config BSP_CH438_INT_PIN GPIO_IRQ_REGISTER %d failed!\n", CH438_INT_PIN); return; } - PinCfg.cmd = GPIO_IRQ_ENABLE; - PinCfg.pin = CH438_INT_PIN; + //disable ch438 int gpio irq + pin_cfg.cmd = GPIO_IRQ_DISABLE; + pin_cfg.pin = CH438_INT_PIN; ret = BusDrvConfigure(ch438_pin->owner_driver, &configure_info); if (ret != EOK) { - KPrintf("config BSP_CH438_INT_PIN %d failed!\n", CH438_INT_PIN); + KPrintf("config BSP_CH438_INT_PIN GPIO_IRQ_DISABLE %d failed!\n", CH438_INT_PIN); return; } - struct SerialCfgParam serial_cfg; - memset(&serial_cfg, 0, sizeof(struct SerialCfgParam)); - configure_info.configure_cmd = OPE_INT; - configure_info.private_data = (void *)&serial_cfg; - - serial_cfg.data_cfg.port_configure = PORT_CFG_INIT; - - serial_cfg.data_cfg.ext_uart_no = 0; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_115200; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 1; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 2; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 3; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 4; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 5; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 6; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); - - serial_cfg.data_cfg.ext_uart_no = 7; - serial_cfg.data_cfg.serial_baud_rate = BAUD_RATE_9600; - BusDrvConfigure(&serial_drv->driver, &configure_info); + //enable ch438 int gpio irq + pin_cfg.cmd = GPIO_IRQ_ENABLE; + pin_cfg.pin = CH438_INT_PIN; + ret = BusDrvConfigure(ch438_pin->owner_driver, &configure_info); + if (ret != EOK) { + KPrintf("config BSP_CH438_INT_PIN GPIO_IRQ_ENABLE %d failed!\n", CH438_INT_PIN); + return; + } } static uint32 ImxrtCh438DevRegister(struct SerialHardwareDevice *serial_dev, char *dev_name) @@ -1272,25 +1243,108 @@ int Imxrt1052HwCh438Init(void) return ret; } -void CH438RegTest(unsigned char num)//for test +#ifdef CH438_EXTUART_TEST +static void CH438RegTest(unsigned char num)//for test { uint8 dat; - KPrintf("current test serilnum: %02x \r\n",offset_addr[num]); - KPrintf("IER: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_IER0_ADDR));//?IER - KPrintf("IIR: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_IIR0_ADDR));//?IIR - KPrintf("LCR: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_LCR0_ADDR));//?LCR - KPrintf("MCR: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_MCR0_ADDR));//?MCR - KPrintf("LSR: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_LSR0_ADDR));//?LSR - KPrintf("MSR: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_MSR0_ADDR));//?MSR - KPrintf("FCR: %02x\r\n",ReadCH438Data(offset_addr[num] | REG_FCR0_ADDR));//?FCR - KPrintf("SSR: %02x\r\n",ReadCH438Data( offset_addr[num] | REG_SSR_ADDR ));//?SSR + KPrintf("current test serial num: %02x \r\n",offset_addr[num]); + KPrintf("IER: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_IER0_ADDR));//IER + KPrintf("IIR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_IIR0_ADDR));//IIR + KPrintf("LCR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_LCR0_ADDR));//LCR + KPrintf("MCR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_MCR0_ADDR));//MCR + KPrintf("LSR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_LSR0_ADDR));//LSR + KPrintf("MSR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_MSR0_ADDR));//MSR + KPrintf("FCR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_FCR0_ADDR));//FCR + KPrintf("SSR: 0x%02x\r\n",ReadCH438Data(offset_addr[num] | REG_SSR_ADDR ));//SSR - KPrintf("SCR0: %02x\r\n",(unsigned short)ReadCH438Data(offset_addr[num] | REG_SCR0_ADDR));//?SCR + KPrintf("SCR0: 0x%02x\r\n",(unsigned short)ReadCH438Data(offset_addr[num] | REG_SCR0_ADDR));//SCR dat = 0x55; WriteCH438Data(offset_addr[num] | REG_SCR0_ADDR, dat); - KPrintf("SCR55: %02x\r\n",(unsigned short)ReadCH438Data(offset_addr[num] | REG_SCR0_ADDR));//?SCR + KPrintf("SCR55: 0x%02x\r\n",(unsigned short)ReadCH438Data(offset_addr[num] | REG_SCR0_ADDR));//SCR dat = 0xAA; WriteCH438Data(offset_addr[num] | REG_SCR0_ADDR, dat); - KPrintf("SCRAA: %02x\r\n",(unsigned short)ReadCH438Data(offset_addr[num] | REG_SCR0_ADDR));//?SCR + KPrintf("SCRAA: 0x%02x\r\n",(unsigned short)ReadCH438Data(offset_addr[num] | REG_SCR0_ADDR));//SCR } + +static struct Bus *bus; +static struct HardwareDev *dev; +static struct Driver *drv; + +static void Ch438Read(void *parameter) +{ + uint8 RevLen; + uint8 ext_uart_no = 0; + uint8 i, cnt = 0; + + struct BusBlockReadParam read_param; + static uint8 Ch438Buff[8][256]; + + struct BusBlockWriteParam write_param; + + while (1) + { + KPrintf("ready to read test_ch438 data\n"); + + read_param.buffer = Ch438Buff[ext_uart_no]; + RevLen = BusDevReadData(dev, &read_param); + + KPrintf("test_ch438 get data %u\n", RevLen); + + if (RevLen) { + for(i = 0 ; i < RevLen; i ++) { + KPrintf("i %u data 0x%x\n", i, Ch438Buff[ext_uart_no][i]); + Ch438Buff[ext_uart_no][i] = 0; + } + + cnt ++; + write_param.buffer = &cnt; + write_param.size = 1; + BusDevWriteData(dev, &write_param); + } + + } +} + +static void TestCh438Init(void) +{ + x_err_t flag; + + struct BusConfigureInfo configure_info; + + bus = BusFind(CH438_BUS_NAME); + drv = BusFindDriver(bus, CH438_DRIVER_NAME); + + dev = BusFindDevice(bus, CH438_DEVICE_NAME_0); + + struct SerialCfgParam serial_cfg; + memset(&serial_cfg, 0, sizeof(struct SerialCfgParam)); + configure_info.configure_cmd = OPE_INT; + configure_info.private_data = (void *)&serial_cfg; + + serial_cfg.data_cfg.port_configure = PORT_CFG_INIT; + + serial_cfg.data_cfg.ext_uart_no = 0; + serial_cfg.data_cfg.serial_baud_rate = 115200; + BusDrvConfigure(drv, &configure_info); + + KPrintf("ready to create test_ch438 task\n"); + + int32 task_CH438_read = KTaskCreate("task_CH438_read", Ch438Read, NONE, 2048, 10); + flag = StartupKTask(task_CH438_read); + if (flag != EOK) { + KPrintf("StartupKTask task_CH438_read failed .\n"); + return; + } +} + +void TestCh438(void) +{ + TestCh438Init(); + + CH438RegTest(0); +} +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), + TestCh438, TestCh438, TestCh438 ); + +#endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c index 58b0ca17a..ddf1ed881 100755 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/gpio/connect_gpio.c @@ -78,6 +78,7 @@ const struct PinMask pin_mask[] = struct PinIrqHdr pin_irq_hdr_tab[] = { /* GPIO1 */ + {-1, 0, NONE, NONE},//1 {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, @@ -108,9 +109,9 @@ struct PinIrqHdr pin_irq_hdr_tab[] = {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, + {-1, 0, NONE, NONE},//32 /* GPIO2 */ + {-1, 0, NONE, NONE},//33 {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, @@ -141,9 +142,9 @@ struct PinIrqHdr pin_irq_hdr_tab[] = {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, + {-1, 0, NONE, NONE},//64 /* GPIO3 */ + {-1, 0, NONE, NONE},//65 {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, @@ -174,8 +175,7 @@ struct PinIrqHdr pin_irq_hdr_tab[] = {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, + {-1, 0, NONE, NONE},//96 /* GPIO4 */ {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, @@ -208,9 +208,9 @@ struct PinIrqHdr pin_irq_hdr_tab[] = {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, - {-1, 0, NONE, NONE}, + {-1, 0, NONE, NONE},//128 /* GPIO5 */ - {-1, 0, NONE, NONE}, + {-1, 0, NONE, NONE},//129 {-1, 0, NONE, NONE}, {-1, 0, NONE, NONE}, }; @@ -581,6 +581,9 @@ static __inline void PinIrqHdr(uint32_t index_offset, uint8_t pin_start, GPIO_Ty if (isr_status & (1 << i)) { GPIO_PortClearInterruptFlags(gpio, (1 << i)); + + __DSB(); + pin = index_offset + i; if (pin_irq_hdr_tab[pin].hdr) { pin_irq_hdr_tab[pin].hdr(pin_irq_hdr_tab[pin].args); diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ch438.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ch438.h index 2a4f2da60..2944ed0a2 100755 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ch438.h +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ch438.h @@ -266,11 +266,7 @@ #define CH438_NWR_PIN IMXRT_GET_PIN(3, 4) #define CH438_NRD_PIN IMXRT_GET_PIN(3, 5) #define CH438_ALE_PIN IMXRT_GET_PIN(3, 2) -#define CH438_INT_PIN IMXRT_GET_PIN(3, 3) -// #define DIR_485CH1_PIN -// #define DIR_485CH2_PIN - -void CH438RegTest(unsigned char num); +#define CH438_INT_PIN IMXRT_GET_PIN(3, 3) int Imxrt1052HwCh438Init(void); From 1cf9939cb2ecc16da1e876f04813839bf932080e Mon Sep 17 00:00:00 2001 From: Wang_Weigen Date: Thu, 24 Mar 2022 15:28:24 +0800 Subject: [PATCH 4/5] add semc driver and eth driver --- Ubiquitous/XiZi/board/xidatong/board.c | 23 + .../board/xidatong/third_party_driver/Kconfig | 12 + .../xidatong/third_party_driver/Makefile | 8 + .../third_party_driver/ethernet/Kconfig | 1 + .../third_party_driver/ethernet/Makefile | 3 + .../ethernet/enet_ethernetif.c | 313 ++ .../ethernet/enet_ethernetif_kinetis.c | 674 ++++ .../ethernet/enet_ethernetif_lpc.c | 960 +++++ .../third_party_driver/ethernet/fsl_enet.c | 3484 +++++++++++++++++ .../ethernet/ksz8081/Makefile | 2 + .../ethernet/ksz8081/fsl_phy.c | 324 ++ .../ethernet/ksz8081/fsl_phy.h | 209 + .../include/connect_ethernet.h | 39 + .../include/enet_ethernetif.h | 192 + .../include/enet_ethernetif_priv.h | 82 + .../third_party_driver/include/fsl_semc.h | 830 ++++ .../xidatong/third_party_driver/semc/Kconfig | 9 + .../xidatong/third_party_driver/semc/Makefile | 3 + .../third_party_driver/semc/connect_semc.c | 57 + .../third_party_driver/semc/fsl_semc.c | 1066 +++++ .../semc/semc_externsdram_test.c | 180 + Ubiquitous/XiZi/path_kernel.mk | 11 + 22 files changed, 8482 insertions(+) create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Kconfig create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_kinetis.c create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_lpc.c create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/fsl_enet.c create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/Makefile create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ethernet.h create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif.h create mode 100755 Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif_priv.h create mode 100644 Ubiquitous/XiZi/board/xidatong/third_party_driver/include/fsl_semc.h create mode 100644 Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Kconfig create mode 100644 Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Makefile create mode 100644 Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/connect_semc.c create mode 100644 Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/fsl_semc.c create mode 100644 Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/semc_externsdram_test.c diff --git a/Ubiquitous/XiZi/board/xidatong/board.c b/Ubiquitous/XiZi/board/xidatong/board.c index 1d8af975a..769b40efa 100644 --- a/Ubiquitous/XiZi/board/xidatong/board.c +++ b/Ubiquitous/XiZi/board/xidatong/board.c @@ -70,6 +70,13 @@ int MountSDCard(void) #include #endif +#ifdef BSP_USING_SEMC +extern status_t BOARD_InitSEMC(void); +#ifdef BSP_USING_EXTSRAM +extern int ExtSramInit(void); +#endif +#endif + void BOARD_SD_Pin_Config(uint32_t speed, uint32_t strength) { IOMUXC_SetPinConfig(IOMUXC_GPIO_SD_B0_00_USDHC1_CMD, @@ -302,6 +309,22 @@ void InitBoardHardware() InitBoardMemory((void *)HEAP_BEGIN, (void *)HEAP_END); +#ifdef BSP_USING_SEMC + CLOCK_InitSysPfd(kCLOCK_Pfd2, 29); + /* Set semc clock to 163.86 MHz */ + CLOCK_SetMux(kCLOCK_SemcMux, 1); + CLOCK_SetDiv(kCLOCK_SemcDiv, 1); + + if (BOARD_InitSEMC() != kStatus_Success) { + KPrintf("\r\n SEMC Init Failed\r\n"); + } +#ifdef MEM_EXTERN_SRAM + else { + ExtSramInit(); + } +#endif +#endif + #ifdef BSP_USING_LPUART Imxrt1052HwUartInit(); #endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig index 3277d6e95..1c4cbea81 100644 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Kconfig @@ -21,6 +21,18 @@ menuconfig 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 + +menuconfig BSP_USING_SEMC + bool "Using SEMC device" + default n + if BSP_USING_SEMC + source "$BSP_DIR/third_party_driver/semc/Kconfig" + endif + menuconfig BSP_USING_SDIO bool "Using SD card device" default n diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile index 7d1446aa2..b439cc98f 100644 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/Makefile @@ -1,5 +1,13 @@ SRC_DIR := common gpio +ifeq ($(CONFIG_BSP_USING_LWIP),y) + SRC_DIR += ethernet +endif + +ifeq ($(CONFIG_BSP_USING_SEMC),y) + SRC_DIR += semc +endif + ifeq ($(CONFIG_BSP_USING_LPUART),y) SRC_DIR += uart endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Kconfig b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Kconfig new file mode 100755 index 000000000..8b1378917 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Kconfig @@ -0,0 +1 @@ + diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile new file mode 100755 index 000000000..14be72829 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := enet_ethernetif.c enet_ethernetif_kinetis.c fsl_enet.c +SRC_DIR := ksz8081 +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c new file mode 100755 index 000000000..d04c8adb3 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif.c @@ -0,0 +1,313 @@ +/* + * 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-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file enet_ethernetif.c + * @brief ethernet drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + +#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(FSL_RTOS_FREE_RTOS) +//#include "FreeRTOS.h" +//#include "event_groups.h" +#endif + +#include "netif/ethernet.h" +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + +#include "fsl_enet.h" +#include "fsl_phy.h" +#include "fsl_gpio.h" +#include "fsl_iomuxc.h" + +#include "sys_arch.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/******************************************************************************* + * Code + ******************************************************************************/ + +void enet_delay(void) +{ + volatile uint32_t i = 0; + for (i = 0; i < 1000000; ++i) + { + __asm("NOP"); /* delay */ + } +} + +void Time_Update_LwIP(void) +{ +} + +void ethernetif_clk_init(void) +{ + const clock_enet_pll_config_t config = {.enableClkOutput = true, .enableClkOutput25M = false, .loopDivider = 1}; + CLOCK_InitEnetPll(&config); + SysTick_Config(USEC_TO_COUNT(1000U, CLOCK_GetFreq(kCLOCK_CoreSysClk))); +} + +void ethernetif_gpio_init(void) +{ + gpio_pin_config_t gpio_config = {kGPIO_DigitalOutput, 0, kGPIO_NoIntmode}; + + IOMUXC_EnableMode(IOMUXC_GPR, kIOMUXC_GPR_ENET1TxClkOutputDir, true); + + GPIO_PinInit(GPIO1, 3, &gpio_config); + GPIO_PinInit(GPIO1, 10, &gpio_config); + /* pull up the ENET_INT before RESET. */ + GPIO_WritePinOutput(GPIO1, 10, 1); + GPIO_WritePinOutput(GPIO1, 3, 0); + enet_delay(); + GPIO_WritePinOutput(GPIO1, 3, 1); +} + +void ETH_BSP_Config(void) +{ + static int flag = 0; + if(flag == 0) + { + ethernetif_clk_init(); + ethernetif_gpio_init(); + flag = 1; + } +} + +void ethernetif_phy_init(struct ethernetif *ethernetif, + const ethernetif_config_t *ethernetifConfig, + enet_config_t *config) +{ + uint32_t sysClock; + status_t status; + bool link = false; + uint32_t count = 0; + phy_speed_t speed; + phy_duplex_t duplex; + + sysClock = CLOCK_GetFreq(ethernetifConfig->clockName); + + LWIP_PLATFORM_DIAG(("Initializing PHY...\r\n")); + + while ((count < ENET_ATONEGOTIATION_TIMEOUT) && (!link)) + { + status = PHY_Init(*ethernetif_enet_ptr(ethernetif), ethernetifConfig->phyAddress, sysClock); + + if (kStatus_Success == status) + { + PHY_GetLinkStatus(*ethernetif_enet_ptr(ethernetif), ethernetifConfig->phyAddress, &link); + } + else if (kStatus_PHY_AutoNegotiateFail == status) + { + LWIP_PLATFORM_DIAG(("PHY Auto-negotiation failed. Please check the ENET cable connection and link partner setting.")); + } + else + { + LWIP_ASSERT("\r\nCannot initialize PHY.\r\n", 0); + } + + count++; + } + + if (link) + { + /* Get the actual PHY link speed. */ + PHY_GetLinkSpeedDuplex(*ethernetif_enet_ptr(ethernetif), ethernetifConfig->phyAddress, &speed, &duplex); + /* Change the MII speed and duplex for actual link status. */ + config->miiSpeed = (enet_mii_speed_t)speed; + config->miiDuplex = (enet_mii_duplex_t)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; + err_t ret = 0; + + 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 ((ret = netif->input(p, netif)) != ERR_OK) + { + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); + lw_print("lw: [%s] ret %d p %p\n", __func__, ret, p); + pbuf_free(p); + p = NULL; + } + } +} + +static ENET_Type *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 enets[arrayIdx]; + } + enetCount++; + } + } + return NULL; +} + +err_t ethernetif_init(struct netif *netif, struct ethernetif *ethernetif, + const uint8_t enetIdx, + 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) = ethernetif_get_enet_base(enetIdx); + 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/xidatong/third_party_driver/ethernet/enet_ethernetif_kinetis.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_kinetis.c new file mode 100755 index 000000000..fe8f7c3d1 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_kinetis.c @@ -0,0 +1,674 @@ +/* + * 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-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file enet_ethernetif_kinetis.c + * @brief ethernet drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + +#include "sys_arch.h" +#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" + +#ifdef FSL_RTOS_XIUOS +#define USE_RTOS 1 +#define FSL_RTOS_FREE_RTOS +#endif + +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + +#ifdef FSL_RTOS_XIUOS +#include "xs_sem.h" + +#else +#include "FreeRTOS.h" +#include "event_groups.h" +#include "list.h" +#endif + +typedef uint32_t TickType_t; +#define portMAX_DELAY ( TickType_t ) 0xffffffffUL + +typedef TickType_t EventBits_t; + +typedef long BaseType_t; +typedef unsigned long UBaseType_t; + +#define portBASE_TYPE long + +#define pdFALSE ( ( BaseType_t ) 0 ) +#define pdTRUE ( ( BaseType_t ) 1 ) + +#define pdPASS ( pdTRUE ) +#define pdFAIL ( pdFALSE ) + +#ifndef FSL_RTOS_XIUOS +typedef struct EventGroupDef_t +{ + EventBits_t uxEventBits; + List_t xTasksWaitingForBits; /*< List of tasks waiting for a bit to be set. */ + + #if ( configUSE_TRACE_FACILITY == 1 ) + UBaseType_t uxEventGroupNumber; + #endif + + #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the event group is statically allocated to ensure no attempt is made to free the memory. */ + #endif +} EventGroup_t; + +struct EventGroupDef_t; +typedef struct EventGroupDef_t * EventGroupHandle_t; +#endif + +#endif + +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + +#include "fsl_enet.h" +#include "fsl_phy.h" + +#include "sys_arch.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/** + * 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) + +#ifdef FSL_RTOS_XIUOS + int enetSemaphore; +#else + EventGroupHandle_t enetTransmitAccessEvent; +#endif + EventBits_t txFlag; +#endif + enet_rx_bd_struct_t *RxBuffDescrip; + enet_tx_bd_struct_t *TxBuffDescrip; + rx_buffer_t *RxDataBuff; + tx_buffer_t *TxDataBuff; +}; + + +/******************************************************************************* + * Code + ******************************************************************************/ +#if USE_RTOS && defined(FSL_RTOS_FREE_RTOS) + +int32 lwip_obtain_semaphore(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + return (KSemaphoreObtain(ethernetif->enetSemaphore, WAITING_FOREVER) == EOK); +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, uint32_t ringId, enet_event_t event, void *param) +#else +static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param) +#endif /* FSL_FEATURE_ENET_QUEUE */ +{ + struct netif *netif = (struct netif *)param; + struct ethernetif *ethernetif = netif->state; + BaseType_t xResult; + + switch (event) + { + case kENET_RxEvent: + ethernetif_input(netif); + break; + case kENET_TxEvent: +#ifndef FSL_RTOS_XIUOS + { + 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); + } + } +#endif + break; + default: + break; + } + + KSemaphoreAbandon(ethernetif->enetSemaphore); +} +#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]; + + /* 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. */ + + sysClock = CLOCK_GetFreq(ethernetifConfig->clockName); + + ENET_GetDefaultConfig(&config); + config.ringNum = ENET_RING_NUM; + + ethernetif_phy_init(ethernetif, ethernetifConfig, &config); + +#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. */ +#ifdef FSL_RTOS_XIUOS + if(ethernetif->enetSemaphore < 0) + { + ethernetif->enetSemaphore = KSemaphoreCreate(0); + } +#else + ethernetif->enetTransmitAccessEvent = xEventGroupCreate(); +#endif + ethernetif->txFlag = 0x1; + + config.interrupt |= kENET_RxFrameInterrupt | kENET_TxFrameInterrupt | kENET_TxBufferInterrupt; + + 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 */ + + /* 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); +// low_level_init(); +} + +ENET_Type **ethernetif_enet_ptr(struct ethernetif *ethernetif) +{ + return &(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; + + lw_print("lw: [%s] len %d\n", __func__, length); + + do + { + result = ENET_SendFrame(ethernetif->base, ðernetif->handle, data, length); + + if (result == kStatus_ENET_TxFrameBusy) + { +#ifdef FSL_RTOS_XIUOS + KSemaphoreObtain(ethernetif->enetSemaphore, portMAX_DELAY); +#else + xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, ethernetif->txFlag, pdTRUE, (BaseType_t) false, + portMAX_DELAY); +#endif + } + + } 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) != kStatus_ENET_TxFrameBusy) + { + return ERR_OK; + } + } + + return ERR_TIMEOUT; + } +#endif +} + +struct pbuf *ethernetif_linkinput(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p = NULL; + struct pbuf *q; + uint32_t len; + status_t status; + + /* Obtain the size of the packet and put it into the "len" + variable. */ + status = ENET_GetRxFrameSize(ðernetif->handle, &len); + + if (kStatus_ENET_RxFrameEmpty != status) + { + /* Call ENET_ReadFrame when there is a received frame. */ + if (len != 0) + { +#if ETH_PAD_SIZE + len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + + /* We allocate a pbuf chain of pbufs from the pool. */ + p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); + + if (p != NULL) + { +#if ETH_PAD_SIZE + pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + if (p->next == 0) /* One-chain buffer.*/ + { + ENET_ReadFrame(ethernetif->base, ðernetif->handle, p->payload, p->len); + } + else /* Multi-chain buffer.*/ + { + uint8_t data_tmp[ENET_FRAME_MAX_FRAMELEN]; + uint32_t data_tmp_len = 0; + + ENET_ReadFrame(ethernetif->base, ðernetif->handle, data_tmp, p->tot_len); + + /* We iterate over the pbuf chain until we have read the entire + * packet into the pbuf. */ + for (q = p; (q != NULL) && ((data_tmp_len + q->len) <= sizeof(data_tmp)); q = q->next) + { + /* Read enough bytes to fill this pbuf in the chain. The + * available data in the pbuf is given by the q->len + * variable. */ + memcpy(q->payload, &data_tmp[data_tmp_len], q->len); + data_tmp_len += q->len; + } + } + + 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); + } +#if ETH_PAD_SIZE + pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + + LINK_STATS_INC(link.recv); + } + else + { + /* drop packet*/ + ENET_ReadFrame(ethernetif->base, ðernetif->handle, NULL, 0U); + + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: Fail to allocate new memory space\n")); + + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + } + else + { + /* Update the received buffer when error happened. */ + if (status == kStatus_ENET_RxFrameError) + { +#if 0 && defined(FSL_FEATURE_SOC_ENET_COUNT) && (FSL_FEATURE_SOC_ENET_COUNT > 0) /* Error statisctics */ + enet_data_error_stats_t eErrStatic; + /* Get the error information of the received g_frame. */ + ENET_GetRxErrBeforeReadFrame(ðernetif->handle, &eErrStatic); +#endif + /* Update the receive buffer. */ + ENET_ReadFrame(ethernetif->base, ðernetif->handle, NULL, 0U); + + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: RxFrameError\n")); + + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + } + } + + 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); + + 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, 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); + + 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, 1U, (ethernetif_config_t *)netif->state); +} +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_lpc.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_lpc.c new file mode 100755 index 000000000..622fb8b2d --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/enet_ethernetif_lpc.c @@ -0,0 +1,960 @@ +/* + * 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-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file enet_ethernetif_lpc.c + * @brief ethernet drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + + +#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/sys.h" +#include "lwip/ethip6.h" +#include "netif/etharp.h" +#include "netif/ppp/pppoe.h" +#include "lwip/igmp.h" +#include "lwip/mld6.h" + +//#if !NO_SYS +//#include "FreeRTOS.h" +//#include "event_groups.h" +//#include "lwip/tcpip.h" +//#endif /* !NO_SYS */ + +#include "enet_ethernetif.h" +#include "enet_ethernetif_priv.h" + +#include "fsl_enet.h" +#include "fsl_phy.h" + +//#if MEM_ALIGNMENT != FSL_ENET_BUFF_ALIGNMENT +///* These two has to match for zero-copy functionality */ +//#error "MEM_ALIGNMENT != FSL_ENET_BUFF_ALIGNMENT" +//#endif /* MEM_ALIGNMENT != FSL_ENET_BUFF_ALIGNMENT */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! + * @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. */ + enet_rx_bd_struct_t* rxDesc; /*!< Descriptor holding the data. */ + struct ethernetif *ethernetif; /*!< Ethernet interface context data. */ + volatile bool ownedByLwip; /*!< If true, descriptor cannot be reused by DMA yet. */ +} rx_pbuf_wrapper_t; + +/*! + * @brief Helper struct to hold private data used to operate + * your ethernet interface. + */ +struct ethernetif +{ + ENET_Type *base; + enet_handle_t handle; +#if !NO_SYS + EventGroupHandle_t enetTransmitAccessEvent; + EventBits_t txFlag; +#endif /* !NO_SYS */ + enet_rx_bd_struct_t *RxBuffDescrip; + enet_tx_bd_struct_t *TxBuffDescrip; + rx_buffer_t *RxDataBuff; + volatile struct pbuf *txPbufs[ENET_TXBD_NUM]; + volatile uint8_t txIdx; + volatile uint8_t txReleaseIdx; + rx_pbuf_wrapper_t rxPbufs[ENET_RXBD_NUM]; + uint8_t rxIdx; + const mem_range_t *non_dma_memory; +}; + +static void ethernetif_tx_release(struct ethernetif *ethernetif); +static void ethernetif_rx_release(struct pbuf *p); + +/******************************************************************************* + * Code + ******************************************************************************/ + +/** + * Called from ENET ISR. + */ +static void ethernet_callback(ENET_Type *base, enet_handle_t *handle, + enet_event_t event, uint8_t channel, void *param) +#if NO_SYS +{ + struct netif *netif = (struct netif *)param; + struct ethernetif *ethernetif = netif->state; + + if (event == kENET_TxIntEvent) + { + ethernetif_tx_release(ethernetif); + } +} +#else +{ + struct netif *netif = (struct netif *)param; + struct ethernetif *ethernetif = netif->state; + BaseType_t xResult; + + switch (event) + { + case kENET_RxIntEvent: + ethernetif_input(netif); + break; + case kENET_TxIntEvent: + { + portBASE_TYPE taskToWake = pdFALSE; + + ethernetif_tx_release(ethernetif); + +#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 /* NO_SYS */ + +#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; + err_t result; + + switch (action) + { + case IGMP_ADD_MAC_FILTER: + /* LPC ENET does not accept multicast selectively, + * so all multicast has to be passed through. */ + ENET_AcceptAllMulticast(ethernetif->base); + result = ERR_OK; + break; + case IGMP_DEL_MAC_FILTER: + /* + * Moves the ENET device from a multicast group. + * Since we don't keep track of which multicast groups + * are still to enabled, the call is commented out. + */ + /* ENET_RejectAllMulticast(ethernetif->base); */ + 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; + err_t result; + + switch (action) + { + case NETIF_ADD_MAC_FILTER: + /* LPC ENET does not accept multicast selectively, + * so all multicast has to be passed through. */ + ENET_AcceptAllMulticast(ethernetif->base); + result = ERR_OK; + break; + case NETIF_DEL_MAC_FILTER: + /* + * Moves the ENET device from a multicast group. + * Since we don't keep track of which multicast groups + * are still to enabled, the call is commented out. + */ + /* ENET_RejectAllMulticast(ethernetif->base); */ + result = ERR_OK; + break; + default: + result = ERR_IF; + break; + } + + return result; +} +#endif + +/** + * Gets the RX descriptor by its index. + */ +static inline enet_rx_bd_struct_t *ethernetif_get_rx_desc( + struct ethernetif *ethernetif, + uint32_t index) +{ + return &(ethernetif->RxBuffDescrip[index]); +} + +/** + * Gets the TX descriptor by its index. + */ +static inline enet_tx_bd_struct_t *ethernetif_get_tx_desc( + struct ethernetif *ethernetif, + uint32_t index) +{ + return &(ethernetif->TxBuffDescrip[index]); +} + +/** + * 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]; + uint32_t rxBufferStartAddr[ENET_RXBD_NUM]; + uint32_t i; + + /* calculate start addresses of all rx buffers */ + for (i = 0; i < ENET_RXBD_NUM; i++) + { + rxBufferStartAddr[i] = (uint32_t)&(ethernetif->RxDataBuff[i][ETH_PAD_SIZE]); + } + + /* prepare the buffer configuration. */ + buffCfg[0].rxRingLen = ENET_RXBD_NUM; /* The length of receive buffer descriptor ring. */ + buffCfg[0].txRingLen = ENET_TXBD_NUM; /* The length of transmit buffer descriptor ring. */ + buffCfg[0].txDescStartAddrAlign = ethernetif_get_tx_desc(ethernetif, 0U); /* Aligned transmit descriptor start address. */ + buffCfg[0].txDescTailAddrAlign = ethernetif_get_tx_desc(ethernetif, 0U); /* Aligned transmit descriptor tail address. */ + buffCfg[0].rxDescStartAddrAlign = ethernetif_get_rx_desc(ethernetif, 0U); /* Aligned receive descriptor start address. */ + buffCfg[0].rxDescTailAddrAlign = ethernetif_get_rx_desc(ethernetif, ENET_RXBD_NUM); /* Aligned receive descriptor tail address. */ + buffCfg[0].rxBufferStartAddr = rxBufferStartAddr; /* Start addresses of the rx buffers. */ + buffCfg[0].rxBuffSizeAlign = sizeof(rx_buffer_t); /* Aligned receive data buffer size. */ + + sysClock = CLOCK_GetFreq(ethernetifConfig->clockName); + + LWIP_ASSERT("ethernetifConfig->non_dma_memory == NULL", (ethernetifConfig->non_dma_memory != NULL)); + ethernetif->non_dma_memory = ethernetifConfig->non_dma_memory; + + ENET_GetDefaultConfig(&config); + config.multiqueueCfg = NULL; + + ethernetif_phy_init(ethernetif, ethernetifConfig, &config); + +#if !NO_SYS + /* Create the Event for transmit busy release trigger. */ + ethernetif->enetTransmitAccessEvent = xEventGroupCreate(); + ethernetif->txFlag = 0x1; +#endif /* !NO_SYS */ + NVIC_SetPriority(ETHERNET_IRQn, ENET_PRIORITY); + + ethernetif->txIdx = 0U; + ethernetif->rxIdx = 0U; + ethernetif->txReleaseIdx = 0U; + + for (i = 0; i < ENET_RXBD_NUM; i++) + { + ethernetif->rxPbufs[i].p.custom_free_function = ethernetif_rx_release; + ethernetif->rxPbufs[i].rxDesc = ðernetif->RxBuffDescrip[i]; + ethernetif->rxPbufs[i].ethernetif = ethernetif; + ethernetif->rxPbufs[i].ownedByLwip = false; + } + + ENET_Init(ethernetif->base, &config, netif->hwaddr, sysClock); + +#if defined(LPC54018_SERIES) + /* Workaround for receive issue on lpc54018 */ + ethernetif->base->MAC_FRAME_FILTER |= ENET_MAC_FRAME_FILTER_RA_MASK; +#endif + + /* Create the handler. */ +#if NO_SYS + ENET_EnableInterrupts(ethernetif->base, kENET_DmaTx); +#else + ENET_EnableInterrupts(ethernetif->base, kENET_DmaTx | kENET_DmaRx); +#endif /* NO_SYS */ + ENET_CreateHandler(ethernetif->base, ðernetif->handle, &config, + &buffCfg[0], ethernet_callback, netif); + + ENET_DescriptorInit(ethernetif->base, &config, &buffCfg[0]); + + /* Active TX/RX. */ + ENET_StartRxTx(ethernetif->base, 1, 1); +} + +ENET_Type **ethernetif_enet_ptr(struct ethernetif *ethernetif) +{ + return &(ethernetif->base); +} + +/** + * Find the ENET instance index from its base address. + */ +static uint32_t ethernetif_get_enet_idx(ENET_Type *base) +{ + static ENET_Type *const s_enetBases[] = ENET_BASE_PTRS; + uint32_t instance; + + for (instance = 0; instance < FSL_FEATURE_SOC_LPC_ENET_COUNT; instance++) + { + if (s_enetBases[instance] == base) + { + break; + } + } + + LWIP_ASSERT("Cannot find ENET instance index from its base address.", + instance < FSL_FEATURE_SOC_LPC_ENET_COUNT); + + return instance; +} + +/** + * Sends (part of) a frame via ENET. + * TODO: Since ENET_SendFrame() could not be used, some functionality it does + * is missing here for now (channel selection depending on AVB content, + * timestamping. + */ +static void ethernetif_send_buffer(struct ethernetif *ethernetif, + unsigned char *data, + const uint32_t length, + struct pbuf *p_to_release, + enet_desc_flag flag) +{ + static const IRQn_Type s_enetIrqId[] = ENET_IRQS; + enet_tx_bd_struct_t *txDesc = ethernetif_get_tx_desc(ethernetif, + ethernetif->txIdx); + ethernetif->txPbufs[ethernetif->txIdx] = p_to_release; + ethernetif->txIdx = (ethernetif->txIdx + 1) % ENET_TXBD_NUM; + + /* Prepare the descriptor for transmit. */ + txDesc->buff1Addr = (uint32_t)data; + txDesc->buff2Addr = (uint32_t)NULL; + txDesc->buffLen = + ENET_TXDESCRIP_RD_BL1(length) | ENET_TXDESCRIP_RD_IOC_MASK; + + txDesc->controlStat = + ENET_TXDESCRIP_RD_FL(length) | ENET_TXDESCRIP_RD_LDFD(flag); + if ((flag & kENET_FirstFlagOnly) == 0) + { + /* + * Submit to DMA if not the first descriptor in chain. + * All the descriptors have to be prepared before the first one + * is flagged for DMA and transfer starts. ENET could output invalid + * frames otherwise (the exception is Store and Forward mode, where + * delays between preparing of descriptors does not matter). + */ + txDesc->controlStat |= ENET_TXDESCRIP_RD_OWN_MASK; + } + + enet_tx_bd_ring_t *txBdRing = (enet_tx_bd_ring_t *) + ðernetif->handle.txBdRing[0]; + + /* + * Increment txDescUsed. + * Without this, callback would not fire from ENET ISR on finished TX. + * This is kind of a hack. Alternative could be to define + * void ETHERNET_DriverIRQHandler(void) and handle IRQs completely + * in this file. + */ + DisableIRQ(s_enetIrqId[ethernetif_get_enet_idx(ethernetif->base)]); + txBdRing->txDescUsed++; + EnableIRQ(s_enetIrqId[ethernetif_get_enet_idx(ethernetif->base)]); +} + +/** + * Reclaims exactly one TX descriptor after its data has been sent out. + * Then the descriptor can be used by application to prepare next data to send. + */ +static void ethernetif_tx_release(struct ethernetif *ethernetif) +{ + LWIP_ASSERT("Attempt to release more TX buffers than acquired.", + ethernetif->txIdx != ethernetif->txReleaseIdx); + enet_tx_bd_struct_t *txDesc + = ðernetif->TxBuffDescrip[ethernetif->txReleaseIdx]; + LWIP_ASSERT("TX buffer still owned by DMA.", + !ENET_IsTxDescriptorDmaOwn(txDesc)); + + struct pbuf *p = (struct pbuf *) + ethernetif->txPbufs[ethernetif->txReleaseIdx]; + if (p != NULL) + { +#if ETH_PAD_SIZE + /* Reclaim the padding, force because it may be REF pbuf. */ + pbuf_header_force(p, ETH_PAD_SIZE); +#endif + +#if NO_SYS +#if defined(LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT) && LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + pbuf_free(p); +#else + #error "Bare metal requires LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT=1 because pbuf_free() is being called from an ISR" +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ +#else + if (pbuf_free_callback(p) != ERR_OK) + { +#if defined(LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT) && LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT + pbuf_free(p); +#else + LWIP_ASSERT("Failed to enqueue pbuf deallocation on tcpip_thread", + 0); +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + } +#endif /* NO_SYS */ + + ethernetif->txPbufs[ethernetif->txReleaseIdx] = NULL; + } + + ethernetif->txReleaseIdx = (ethernetif->txReleaseIdx + 1) % ENET_TXBD_NUM; +} + +/** + * Reclaims RX descriptor which holds the p's buffer after p is no longer used + * by the application / lwIP. The DMA can receive new data into + * the descriptor's buffer then. + * Note that RX buffers may be freed by lwIP out of the order in which they were + * passed to lwIP. Therefore there may be spaces between the RX descriptors + * flagged as owned by DMA and DMA could still wait until it's actual position + * is released. + */ +static void ethernetif_rx_release(struct pbuf *p) +{ + SYS_ARCH_DECL_PROTECT(old_level); + rx_pbuf_wrapper_t *wrapper = (rx_pbuf_wrapper_t *)p; +#if NO_SYS + bool intEnable = false; +#else + bool intEnable = true; +#endif /* NO_SYS */ + + SYS_ARCH_PROTECT(old_level); + + wrapper->ownedByLwip = false; + + /* Update the receive buffer descriptor. */ + ENET_UpdateRxDescriptor(wrapper->rxDesc, NULL, NULL, intEnable, false); + ENET_UpdateRxDescriptorTail(wrapper->ethernetif->base, 0U, + (uint32_t)ethernetif_get_rx_desc(wrapper->ethernetif, ENET_RXBD_NUM)); + + SYS_ARCH_UNPROTECT(old_level); +} + +/** + * Gets the length of a received frame (if there is some). + */ +static status_t ethernetif_get_rx_frame_size(struct ethernetif *ethernetif, + uint32_t *length) +{ + uint8_t index = ethernetif->rxIdx; + enet_rx_bd_struct_t *rxDesc; + uint32_t rxControl; + + /* Reset the length to zero. */ + *length = 0; + + do + { + rxDesc = ethernetif_get_rx_desc(ethernetif, index); + rxControl = ENET_GetRxDescriptor(rxDesc); + + if ((rxControl & ENET_RXDESCRIP_WR_OWN_MASK) + || (ethernetif->rxPbufs[index].ownedByLwip)) + { + /* + * Buffer descriptor is owned by DMA or lwIP. + * We haven't received any complete frame yet. + */ + return kStatus_ENET_RxFrameEmpty; + } + + /* Application owns the buffer descriptor. */ + if (rxControl & ENET_RXDESCRIP_WR_LD_MASK) + { + /* It's last descriptor of a frame, get its status or length. */ + if (rxControl & ENET_RXDESCRIP_WR_ERRSUM_MASK) + { + return kStatus_ENET_RxFrameError; + } + else + { + *length = rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK; + return kStatus_Success; + } + } + + index = (index + 1U) % ENET_RXBD_NUM; + } while (index != ethernetif->rxIdx); + + /* + * All descriptors have data but the end of the frame not detected. + */ + return kStatus_ENET_RxFrameError; +} + +/** + * Drops (releases) receive descriptors until the last one of a frame is reached + * or drops entire descriptor ring when all descriptors have data but end + * of the frame not detected among them. + * Function can be called only after ethernetif_get_rx_frame_size() indicates + * that there actually is a frame error or a received frame. + */ +static void ethernetif_drop_frame(struct ethernetif *ethernetif) +{ +#if NO_SYS + bool intEnable = false; +#else + bool intEnable = true; +#endif /* NO_SYS */ + + enet_rx_bd_struct_t *rxDesc; + uint8_t index = ethernetif->rxIdx; + uint32_t rxControl; + + do + { + rxDesc = ethernetif_get_rx_desc(ethernetif, ethernetif->rxIdx); + ethernetif->rxIdx = (ethernetif->rxIdx + 1U) % ENET_RXBD_NUM; + rxControl = ENET_GetRxDescriptor(rxDesc); + + /* Update the receive buffer descriptor. */ + ENET_UpdateRxDescriptor(rxDesc, NULL, NULL, intEnable, false); + + /* Find the last buffer descriptor for the frame. */ + if (rxControl & ENET_RXDESCRIP_WR_LD_MASK) + { + break; + } + } while (ethernetif->rxIdx != index); + + ENET_UpdateRxDescriptorTail(ethernetif->base, 0U, + (uint32_t)ethernetif_get_rx_desc(ethernetif, ENET_RXBD_NUM)); +} + +/** + * Reads a received frame - wraps its descriptor buffer(s) into a pbuf + * or a pbuf chain, flag descriptors as owned by lwIP and returns the pbuf. + * The descriptors are returned to DMA only after the returned pbuf is released. + * Function can be called only after ethernetif_get_rx_frame_size() 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; + enet_rx_bd_struct_t *rxDesc; + uint32_t rxControl; + uint32_t len = 0; + struct pbuf *p = NULL; + struct pbuf *q = NULL; + + do + { + wrapper = ðernetif->rxPbufs[ethernetif->rxIdx]; + wrapper->ownedByLwip = true; + ethernetif->rxIdx = (ethernetif->rxIdx + 1U) % ENET_RXBD_NUM; + + rxDesc = wrapper->rxDesc; + rxControl = ENET_GetRxDescriptor(rxDesc); + + len = (rxControl & ENET_RXDESCRIP_WR_PACKETLEN_MASK); + + /* Wrap the receive buffer in pbuf. */ + if (p == NULL) + { + p = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &wrapper->p, + (void *)rxDesc->buff1Addr, len); + LWIP_ASSERT("pbuf_alloced_custom() failed", p); + +#if ETH_PAD_SIZE + /* Add the padding header, force because it is a REF type buffer. */ + pbuf_header_force(p, ETH_PAD_SIZE); +#endif + } + else + { + q = pbuf_alloced_custom(PBUF_RAW, len, PBUF_REF, &wrapper->p, + (void *)rxDesc->buff1Addr, len); + LWIP_ASSERT("pbuf_alloced_custom() failed", q); + + pbuf_cat(p, q); + } + } while (((rxControl & ENET_RXDESCRIP_WR_LD_MASK) == 0U) + && (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; +} + +/** + * Attempts to read a frame from ENET and returns it wrapped in a pbuf + * or returns NULL when no frame is received. Discards invalid frames. + */ +struct pbuf *ethernetif_linkinput(struct netif *netif) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *p = NULL; + uint32_t len; + status_t status; + + /* Obtain the size of the packet and put it into the "len" variable. */ + status = ethernetif_get_rx_frame_size(ethernetif, &len); + + if (status == kStatus_Success) + { + p = ethernetif_read_frame(ethernetif, len); + + if (p == NULL) + { + /* Could not initialise wrapper pbuf(s) - drop the frame. */ + ethernetif_drop_frame(ethernetif); + + LWIP_DEBUGF(NETIF_DEBUG, + ("ethernetif_linkinput: Fail to allocate new memory space\n")); + + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + } + else if (status == kStatus_ENET_RxFrameError) + { + /* Update the received buffer when error happened. */ + ethernetif_drop_frame(ethernetif); + + LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_linkinput: RxFrameError\n")); + + LINK_STATS_INC(link.drop); + MIB2_STATS_NETIF_INC(netif, ifindiscards); + } + + return p; +} + +/** + * Returns the number of TX descriptors which could be used by lwIP/application + * to put new TX data into. + * + * The max number of free descriptors is (ENET_TXBD_NUM - 1), that is when + * ethernetif->txReleaseIdx == ethernetif->txIdx. Having the capacity decreased + * by one allows to avoid locking: txReleaseIdx is advanced only from ISR + * and txIdx from tcpip_thread/main loop. Should we use full capacity and have + * some variable to indicate between the "all buffers are free" vs. "all buffers + * are used" situation, it would be manipulated from two contexts hence locking + * would be needed. + */ +static inline int ethernetif_avail_tx_descs(struct ethernetif *ethernetif) +{ + return (ethernetif->txReleaseIdx + ENET_TXBD_NUM - 1 - ethernetif->txIdx) + % ENET_TXBD_NUM; +} + +/** + * Attempts to output a frame from ENET. The function avoids copying of + * p's payload when possible. In such situation it increases p's reference count + * and decreases it (and possibly releases p) after the payload is sent. + */ +err_t ethernetif_linkoutput(struct netif *netif, struct pbuf *p) +{ + struct ethernetif *ethernetif = netif->state; + struct pbuf *q; + struct pbuf *pbuf_to_free = NULL; + struct pbuf *p_copy; + uint16_t clen; + bool copy = false; + const mem_range_t *non_dma_memory; + uint8_t *dst; + uint32_t cnt = 0; + uint8_t first_idx; + uint32_t tail_address; + + LWIP_ASSERT("Output packet buffer empty", p); + + if ((p->tot_len - ETH_PAD_SIZE) > ENET_FRAME_MAX_FRAMELEN) + { + return ERR_BUF; + } + + clen = pbuf_clen(p); + + /* Check if relocation is needed */ + + if (clen > (ENET_TXBD_NUM - 1)) + { + /* Pbuf chain is too long to be prepared for DMA at once. */ + copy = true; + } + + for (q = p; (q != NULL) && !copy; q = q->next) + { + /* + * Check if payload is aligned is not desired: lwIP creates RAM pbufs + * in a way that the data coming after the headers are aligned, but not + * the beginning of the ethernet header. LPC ENET DMA will read from + * the aligned address, which is ok, because there is additional space + * before the headers to make up for alignment - so DMA will not read + * from invalid address or unrelated data. + */ + + /* Check payload address is usable by ENET DMA */ + for (non_dma_memory = ethernetif->non_dma_memory; + (non_dma_memory->start != 0U) + || (non_dma_memory->end != 0U); non_dma_memory++) + { + if ((q->payload >= (void *) non_dma_memory->start) + && (q->payload < (void *) non_dma_memory->end)) + { + copy = true; + break; + } + } + } + + if (copy) + { + /* Pbuf needs to be copied. */ + + p_copy = pbuf_alloc(PBUF_RAW, (uint16_t) p->tot_len, PBUF_POOL); + if (p_copy == NULL) + { + return ERR_MEM; + } + + dst = (uint8_t *) p_copy->payload; + for (q = p; q != NULL; q = q->next) + { + LWIP_ASSERT("Copied bytes would exceed p->tot_len", + (q->len + dst - (uint8_t *) p_copy->payload) <= p->tot_len); + memcpy(dst, (uint8_t *)q->payload, q->len); + dst += q->len; + } + LWIP_ASSERT("Copied bytes != p->tot_len", + (dst - (uint8_t *) p_copy->payload) == p->tot_len); + p_copy->len = p_copy->tot_len = p->tot_len; + + p = p_copy; + } + else + { + /* + * Increase reference count so p is released only after it is sent. + * For copied pbuf, ref is already 1 after pbuf_alloc(). + */ + pbuf_ref(p); + } + + /* + * Wait until the sufficient number of descriptors are available, + * as we have to start the transfer of the first buffer only + * after all buffers in chain are prepared. + */ + while (ethernetif_avail_tx_descs(ethernetif) < clen) + { +#if !NO_SYS + xEventGroupWaitBits(ethernetif->enetTransmitAccessEvent, + ethernetif->txFlag, pdTRUE, (BaseType_t) false, + portMAX_DELAY); +#endif /* !NO_SYS */ + cnt++; + if (cnt >= ENET_TIMEOUT) + { + return ERR_TIMEOUT; + } + } + +#if ETH_PAD_SIZE + /* Drop the padding. */ + pbuf_header(p, -ETH_PAD_SIZE); +#endif + + /* Initiate transfer. */ + + first_idx = ethernetif->txIdx; + + for (q = p; q != NULL; q = q->next) + { + enet_desc_flag flag = kENET_MiddleFlag; + pbuf_to_free = NULL; + + if (q == p) + { + flag |= kENET_FirstFlagOnly; + } + + if (q->next == NULL) + { + flag |= kENET_LastFlagOnly; + + /* On last TX interrupt, free pbuf chain. */ + pbuf_to_free = p; + } + + ethernetif_send_buffer(ethernetif, q->payload, q->len, pbuf_to_free, + flag); + } + + /* All pbufs from chain are prepared, allow DMA to access the first one. */ + ethernetif_get_tx_desc(ethernetif, first_idx)->controlStat |= + ENET_TXDESCRIP_RD_OWN_MASK; + + /* Update the transmit tail address. */ + if (ethernetif->txIdx == 0U) + { + tail_address = (uint32_t)ethernetif_get_tx_desc(ethernetif, + ENET_TXBD_NUM); + } + else + { + tail_address = (uint32_t)ethernetif_get_tx_desc(ethernetif, + ethernetif->txIdx); + } + ENET_UpdateTxDescriptorTail(ethernetif->base, 0, tail_address); + + MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len); + if (((uint8_t *)p->payload)[0] & 1) + { + /* broadcast or multicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts); + } + else + { + /* unicast packet */ + MIB2_STATS_NETIF_INC(netif, ifoutucastpkts); + } + LINK_STATS_INC(link.xmit); + + return ERR_OK; +} + +/** + * 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); + + ethernetif_0.RxBuffDescrip = &(rxBuffDescrip_0[0]); + ethernetif_0.TxBuffDescrip = &(txBuffDescrip_0[0]); + ethernetif_0.RxDataBuff = &(rxDataBuff_0[0]); + + return ethernetif_init(netif, ðernetif_0, 0U, (ethernetif_config_t *)netif->state); +} + +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_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); + + ethernetif_1.RxBuffDescrip = &(rxBuffDescrip_1[0]); + ethernetif_1.TxBuffDescrip = &(txBuffDescrip_1[0]); + ethernetif_1.RxDataBuff = &(rxDataBuff_1[0]); + + return ethernetif_init(netif, ðernetif_1, 1U, (ethernetif_config_t *)netif->state); +} +#endif /* FSL_FEATURE_SOC_*_ENET_COUNT */ diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/fsl_enet.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/fsl_enet.c new file mode 100755 index 000000000..cd73be820 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/fsl_enet.c @@ -0,0 +1,3484 @@ +/* + * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc. + * Copyright 2016-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file fsl_enet.c + * @brief ethernet drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + +#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 */ + +#include "lwipopts.h" +#include + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.enet" +#endif + +/*! @brief IPv4 PTP message IP version offset. */ +#define ENET_PTP1588_IPVERSION_OFFSET 0x0EU +/*! @brief IPv4 PTP message UDP protocol offset. */ +#define ENET_PTP1588_IPV4_UDP_PROTOCOL_OFFSET 0x17U +/*! @brief IPv4 PTP message UDP port offset. */ +#define ENET_PTP1588_IPV4_UDP_PORT_OFFSET 0x24U +/*! @brief IPv4 PTP message UDP message type offset. */ +#define ENET_PTP1588_IPV4_UDP_MSGTYPE_OFFSET 0x2AU +/*! @brief IPv4 PTP message UDP version offset. */ +#define ENET_PTP1588_IPV4_UDP_VERSION_OFFSET 0x2BU +/*! @brief IPv4 PTP message UDP clock id offset. */ +#define ENET_PTP1588_IPV4_UDP_CLKID_OFFSET 0x3EU +/*! @brief IPv4 PTP message UDP sequence id offset. */ +#define ENET_PTP1588_IPV4_UDP_SEQUENCEID_OFFSET 0x48U +/*! @brief IPv4 PTP message UDP control offset. */ +#define ENET_PTP1588_IPV4_UDP_CTL_OFFSET 0x4AU +/*! @brief IPv6 PTP message UDP protocol offset. */ +#define ENET_PTP1588_IPV6_UDP_PROTOCOL_OFFSET 0x14U +/*! @brief IPv6 PTP message UDP port offset. */ +#define ENET_PTP1588_IPV6_UDP_PORT_OFFSET 0x38U +/*! @brief IPv6 PTP message UDP message type offset. */ +#define ENET_PTP1588_IPV6_UDP_MSGTYPE_OFFSET 0x3EU +/*! @brief IPv6 PTP message UDP version offset. */ +#define ENET_PTP1588_IPV6_UDP_VERSION_OFFSET 0x3FU +/*! @brief IPv6 PTP message UDP clock id offset. */ +#define ENET_PTP1588_IPV6_UDP_CLKID_OFFSET 0x52U +/*! @brief IPv6 PTP message UDP sequence id offset. */ +#define ENET_PTP1588_IPV6_UDP_SEQUENCEID_OFFSET 0x5CU +/*! @brief IPv6 PTP message UDP control offset. */ +#define ENET_PTP1588_IPV6_UDP_CTL_OFFSET 0x5EU +/*! @brief PTPv2 message Ethernet packet type offset. */ +#define ENET_PTP1588_ETHL2_PACKETTYPE_OFFSET 0x0CU +/*! @brief PTPv2 message Ethernet message type offset. */ +#define ENET_PTP1588_ETHL2_MSGTYPE_OFFSET 0x0EU +/*! @brief PTPv2 message Ethernet version type offset. */ +#define ENET_PTP1588_ETHL2_VERSION_OFFSET 0X0FU +/*! @brief PTPv2 message Ethernet clock id offset. */ +#define ENET_PTP1588_ETHL2_CLOCKID_OFFSET 0x22 +/*! @brief PTPv2 message Ethernet sequence id offset. */ +#define ENET_PTP1588_ETHL2_SEQUENCEID_OFFSET 0x2c +/*! @brief Packet type Ethernet IEEE802.3 for PTPv2. */ +#define ENET_ETHERNETL2 0x88F7U +/*! @brief Packet type IPv4. */ +#define ENET_IPV4 0x0800U +/*! @brief Packet type IPv6. */ +#define ENET_IPV6 0x86ddU +/*! @brief Packet type VLAN. */ +#define ENET_8021QVLAN 0x8100U +/*! @brief UDP protocol type. */ +#define ENET_UDPVERSION 0x0011U +/*! @brief Packet IP version IPv4. */ +#define ENET_IPV4VERSION 0x0004U +/*! @brief Packet IP version IPv6. */ +#define ENET_IPV6VERSION 0x0006U +/*! @brief Ethernet mac address length. */ +#define ENET_FRAME_MACLEN 6U +/*! @brief Ethernet VLAN header length. */ +#define ENET_FRAME_VLAN_TAGLEN 4U +/*! @brief MDC frequency. */ +#define ENET_MDC_FREQUENCY 2500000U +/*! @brief NanoSecond in one second. */ +#define ENET_NANOSECOND_ONE_SECOND 1000000000U +/*! @brief Define a common clock cycle delays used for time stamp capture. */ +#ifndef ENET_1588TIME_DELAY_COUNT +#define ENET_1588TIME_DELAY_COUNT 10U +#endif + +/*! @brief Defines the macro for converting constants from host byte order to network byte order. */ +#define ENET_HTONS(n) __REV16(n) +#define ENET_HTONL(n) __REV(n) +#define ENET_NTOHS(n) __REV16(n) +#define ENET_NTOHL(n) __REV(n) + +/*! @brief Define the ENET ring/class bumber . */ +enum _enet_ring_number +{ + 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 */ +}; + +/*! @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); + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @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); +/*! + * @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); +/*! + * @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_QUEUE - 1. + * 0 ----- for single ring kinetis platform. + * 0 ~ 2 for mulit-ring supported IMX8qm. + */ +static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint32_t ringId); + +/*! + * @brief Activates ENET send for multiple tx rings. + * + * @param base ENET peripheral base address. + * @param ringId The descriptor ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1. + * 0 ----- for single ring kinetis platform. + * 0 ~ 2 for mulit-ring supported IMX8qm. + * + * @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. + */ +static void ENET_ActiveSend(ENET_Type *base, uint32_t ringId); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * @brief Parses the ENET frame for time-stamp process of PTP 1588 frame. + * + * @param data The ENET read data for frame parse. + * @param ptpTsData The ENET PTP message and time-stamp data pointer. + * @param isFastEnabled The fast parse flag. + * - true , Fast processing, only check if this is a PTP message. + * - false, Store the PTP message data after check the PTP message. + */ +static bool ENET_Ptp1588ParseFrame(const uint8_t *data, enet_ptp_time_data_t *ptpTsData, bool isFastEnabled); + +/*! + * @brief Updates the new PTP 1588 time-stamp to the time-stamp buffer ring. + * + * @param ptpTsDataRing The PTP message and time-stamp data ring pointer. + * @param ptpTimeData The new PTP 1588 time-stamp data pointer. + */ +static status_t ENET_Ptp1588UpdateTimeRing(enet_ptp_time_data_ring_t *ptpTsDataRing, enet_ptp_time_data_t *ptpTimeData); + +/*! + * @brief Search up the right PTP 1588 time-stamp from the time-stamp buffer ring. + * + * @param ptpTsDataRing The PTP message and time-stamp data ring pointer. + * @param ptpTimeData The find out right PTP 1588 time-stamp data pointer with the specific PTP message. + */ +static status_t ENET_Ptp1588SearchTimeRing(enet_ptp_time_data_ring_t *ptpTsDataRing, enet_ptp_time_data_t *ptpTimedata); + +/*! + * @brief Store the transmit time-stamp for event PTP frame in the time-stamp buffer ring. + * + * @param base ENET peripheral base address. + * @param handle The ENET handle pointer. + * @param ringId The descriptor ring index, range from 0 ~ FSL_FEATURE_ENET_QUEUE - 1. + * 0 ----- for single ring kinetis platform. + * 0 ~ 2 for mulit-ring supported IMX8qm. + */ +static status_t ENET_StoreTxFrameTime(ENET_Type *base, enet_handle_t *handle, uint32_t ringId); + +/*! + * @brief Store the receive time-stamp for event PTP frame in the time-stamp buffer ring. + * + * @param base ENET peripheral base address. + * @param handle The ENET handle pointer. + * @param ptpTimeData The PTP 1588 time-stamp data pointer. + */ +static status_t ENET_StoreRxFrameTime(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_data_t *ptpTimeData); + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_AVB +/*! + * @brief Gets the ring index for transmission. + * + * @param base ENET peripheral base address. + * @param data The ENET transmit data. + * @param handle The ENET handle pointer. + * + * @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. + */ +static uint8_t ENET_GetTxRingId(ENET_Type *base, uint8_t *data, enet_handle_t *handle); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +/******************************************************************************* + * Variables + ******************************************************************************/ + +/*! @brief Pointers to enet handles for each instance. */ +static enet_handle_t *s_ENETHandle[FSL_FEATURE_SOC_ENET_COUNT] = {NULL}; + +/*! @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_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; + +/* ENET ISR for transactional APIs. */ +#if FSL_FEATURE_ENET_QUEUE > 1 +static enet_isr_ring_t s_enetTxIsr; +static enet_isr_ring_t s_enetRxIsr; +#else +static enet_isr_t s_enetTxIsr; +static enet_isr_t s_enetRxIsr; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +static enet_isr_t s_enetErrIsr; +static enet_isr_t s_enetTsIsr; +/******************************************************************************* + * Code + ******************************************************************************/ + +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); + + /* Initializes the MAC configure structure to zero. */ + 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 ungates the module clock and initializes it with the ENET configuration. + * + * 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. + * + * 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(). + */ +void 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) +{ + /* Checks input parameters. */ + assert(handle); + assert(config); + assert(bufferConfig); + assert(macAddr); + assert(config->ringNum <= FSL_FEATURE_ENET_QUEUE); + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + uint32_t instance = ENET_GetInstance(base); + + /* Ungate ENET clock. */ + CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + /* Reset ENET module. */ + ENET_Reset(base); + + /* 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); +} + +/*! + * 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) +{ + /* Disable interrupt. */ + base->EIMR = 0; + + /* Disable ENET. */ + base->ECR &= ~ENET_ECR_ETHEREN_MASK; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disables the clock source. */ + CLOCK_DisableClock(s_enetClock[ENET_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Sets the callback function. + * 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) +{ + assert(handle); + + /* Set callback and userData. */ + handle->callback = callback; + handle->userData = userData; +} + +static void ENET_SetHandler(ENET_Type *base, + enet_handle_t *handle, + const enet_config_t *config, + const enet_buffer_config_t *bufferConfig) +{ + uint8_t count; + uint32_t instance = ENET_GetInstance(base); + const enet_buffer_config_t *buffCfg = bufferConfig; + + /* Store transfer parameters in handle pointer. */ + memset(handle, 0, sizeof(enet_handle_t)); + + handle->ringNum = (config->ringNum > FSL_FEATURE_ENET_QUEUE) ? FSL_FEATURE_ENET_QUEUE : config->ringNum; + for (count = 0; count < handle->ringNum; count++) + { + assert(buffCfg->rxBuffSizeAlign * buffCfg->rxBdNumber > config->rxMaxFrameLen); + + handle->rxBdBase[count] = buffCfg->rxBdStartAddrAlign; + handle->rxBdCurrent[count] = buffCfg->rxBdStartAddrAlign; + handle->rxBuffSizeAlign[count] = buffCfg->rxBuffSizeAlign; + handle->txBdBase[count] = buffCfg->txBdStartAddrAlign; + handle->txBdCurrent[count] = buffCfg->txBdStartAddrAlign; + handle->txBuffSizeAlign[count] = buffCfg->txBuffSizeAlign; + + buffCfg++; + } + + /* Save the handle pointer in the global variables. */ + s_ENETHandle[instance] = handle; + + /* Set the IRQ handler when the interrupt is enabled. */ + if (config->interrupt & ENET_TX_INTERRUPT) + { + s_enetTxIsr = ENET_TransmitIRQHandler; + EnableIRQ(s_enetTxIrqId[instance]); + } + if (config->interrupt & ENET_RX_INTERRUPT) + { + s_enetRxIsr = ENET_ReceiveIRQHandler; + EnableIRQ(s_enetRxIrqId[instance]); + } + if (config->interrupt & ENET_ERR_INTERRUPT) + { + s_enetErrIsr = ENET_ErrorIRQHandler; + EnableIRQ(s_enetErrIrqId[instance]); + } +} + +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 + /* 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; + + /* Maximum frame length check. */ + if ((macSpecialConfig & kENET_ControlVLANTagEnable) && (maxFrameLen <= ENET_FRAME_MAX_FRAMELEN)) + { + maxFrameLen = (ENET_FRAME_MAX_FRAMELEN + ENET_FRAME_VLAN_TAGLEN); +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (macSpecialConfig & kENET_ControlSVLANEnable) + { + /* Double vlan tag (SVLAN) supported. */ + maxFrameLen += ENET_FRAME_VLAN_TAGLEN; + } + ecr |= ((macSpecialConfig & kENET_ControlSVLANEnable) ? (ENET_ECR_SVLANEN_MASK | ENET_ECR_SVLANDBL_MASK) : 0) | + ((macSpecialConfig & kENET_ControlVLANUseSecondTag) ? ENET_ECR_VLANUSE2ND_MASK : 0); +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + } + + /* Configures MAC receive controller with user configure structure. */ + rcr = ((macSpecialConfig & kENET_ControlRxPayloadCheckEnable) ? ENET_RCR_NLC_MASK : 0) | + ((macSpecialConfig & kENET_ControlFlowControlEnable) ? ENET_RCR_CFEN_MASK : 0) | + ((macSpecialConfig & kENET_ControlFlowControlEnable) ? ENET_RCR_FCE_MASK : 0) | + ((macSpecialConfig & kENET_ControlRxPadRemoveEnable) ? ENET_RCR_PADEN_MASK : 0) | + ((macSpecialConfig & kENET_ControlRxBroadCastRejectEnable) ? ENET_RCR_BC_REJ_MASK : 0) | + ((macSpecialConfig & kENET_ControlPromiscuousEnable) ? ENET_RCR_PROM_MASK : 0) | + 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 (config->miiMode == kENET_RgmiiMode) + { + rcr |= ENET_RCR_RGMII_EN_MASK; + rcr &= ~ENET_RCR_MII_MODE_MASK; + } + else + { + rcr &= ~ENET_RCR_RGMII_EN_MASK; +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + rcr |= ENET_RCR_MII_MODE_MASK; + if (config->miiMode == kENET_RmiiMode) + { + rcr |= ENET_RCR_RMII_MODE_MASK; + } +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + /* Speed. */ + if (config->miiSpeed == kENET_MiiSpeed10M) + { + rcr |= ENET_RCR_RMII_10T_MASK; + } +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + if (config->miiSpeed == kENET_MiiSpeed1000M) + { + ecr |= ENET_ECR_SPEED_MASK; + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + + /* Receive setting for half duplex. */ + if (config->miiDuplex == kENET_MiiHalfDuplex) + { + rcr |= ENET_RCR_DRT_MASK; + } + /* Sets internal loop only for MII mode. */ + if ((config->macSpecialConfig & 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 |= (config->miiDuplex ? ENET_TCR_FDEN_MASK : 0) | + ((macSpecialConfig & kENET_ControlMacAddrInsert) ? ENET_TCR_ADDINS_MASK : 0); + 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 (macSpecialConfig & 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 (macSpecialConfig & kENET_ControlStoreAndFwdDisable) + { + /* Transmit fifo watermark settings. */ + base->TFWR = config->txFifoWatermark & ENET_TFWR_TFWR_MASK; + /* Receive fifo full threshold settings. */ + base->RSFL = config->rxFifoFullThreshold & ENET_RSFL_RX_SECTION_FULL_MASK; + } + else + { + /* Transmit fifo watermark settings. */ + base->TFWR = ENET_TFWR_STRFWD_MASK; + base->RSFL = 0; + } + + /* Enable store and forward when accelerator is enabled */ + if (config->txAccelerConfig & (kENET_TxAccelIpCheckEnabled | kENET_TxAccelProtoCheckEnabled)) + { + base->TFWR = ENET_TFWR_STRFWD_MASK; + } + if (config->rxAccelerConfig & (kENET_RxAccelIpCheckEnabled | 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 = bufferConfig->rxBuffSizeAlign; + +#if defined(FSL_FEATURE_ENET_HAS_AVB) && FSL_FEATURE_ENET_HAS_AVB + const enet_buffer_config_t *buffCfg = bufferConfig; + + if (config->ringNum > 1) + { + /* 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 = 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 > 2) + { + /* 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 = buffCfg->rxBuffSizeAlign; + /* Enable the DMAC for ring 2 and with no rx classification set. */ + base->DMACFG[1] = ENET_DMACFG_DMA_CLASS_EN_MASK; + } + + /* Default 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 support 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, !!(config->macSpecialConfig & kENET_ControlSMIPreambleDisable)); + } + +/* 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 + if (config->intCoalesceCfg) + { + uint32_t intMask = (ENET_EIMR_TXB_MASK | ENET_EIMR_RXB_MASK); + +#if FSL_FEATURE_ENET_QUEUE > 1 + uint8_t queue = 0; + 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. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + for (queue = 0; queue < FSL_FEATURE_ENET_QUEUE; 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; + } +#else + base->TXIC = ENET_TXIC_ICFT(config->intCoalesceCfg->txCoalesceFrameCount[0]) | + config->intCoalesceCfg->txCoalesceTimeCount[0] | ENET_TXIC_ICCS_MASK | ENET_TXIC_ICEN_MASK; + base->RXIC = ENET_RXIC_ICFT(config->intCoalesceCfg->rxCoalesceFrameCount[0]) | + config->intCoalesceCfg->rxCoalesceTimeCount[0] | ENET_RXIC_ICCS_MASK | ENET_RXIC_ICEN_MASK; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } +#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); + assert(bufferConfig); + + /* Default single ring is supported. */ + uint8_t ringNum; + uint32_t count; + uint32_t txBuffSizeAlign; + uint8_t *txBuffer; + const enet_buffer_config_t *buffCfg = bufferConfig; + + /* Check the input parameters. */ + for (ringNum = 0; ringNum < config->ringNum; ringNum++) + { + if ((buffCfg->txBdStartAddrAlign > 0) && (buffCfg->txBufferAlign > 0)) + { + volatile enet_tx_bd_struct_t *curBuffDescrip = buffCfg->txBdStartAddrAlign; + txBuffSizeAlign = buffCfg->txBuffSizeAlign; +#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++) + { + /* 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 - 1) + { + 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 |= 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); + assert(bufferConfig); + + /* Default single ring is supported. */ + uint8_t ringNum; + uint32_t count; + uint32_t rxBuffSizeAlign; + uint8_t *rxBuffer; + const enet_buffer_config_t *buffCfg = bufferConfig; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint32_t mask = (kENET_RxFrameInterrupt | 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 == 1) + { + mask = (kENET_RxFrame1Interrupt | kENET_RxBuffer1Interrupt); + } + else if (ringNum == 2) + { + mask = (kENET_RxFrame2Interrupt | kENET_RxBuffer2Interrupt); + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + if ((buffCfg->rxBdStartAddrAlign > 0) && (buffCfg->rxBufferAlign > 0)) + { + 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 + /* Invalidate rx buffers before DMA transfer data into them. */ + DCACHE_InvalidateByRange((uint32_t)rxBuffer, (buffCfg->rxBdNumber * rxBuffSizeAlign)); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + for (count = 0; count < buffCfg->rxBdNumber; count++) + { + /* Set data buffer and the length. */ + curBuffDescrip->buffer = (uint8_t *)((uint32_t)&rxBuffer[count * rxBuffSizeAlign]); + curBuffDescrip->length = 0; + + /* 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 - 1) + { + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + } + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (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++; + } +} + +static void ENET_ActiveSend(ENET_Type *base, uint32_t ringId) +{ + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + /* Ensure previous data update is completed with Data Synchronization Barrier before activing Tx BD. */ + __DSB(); + + switch (ringId) + { + case kENET_Ring0: + base->TDAR = ENET_TDAR_TDAR_MASK; + break; +#if FSL_FEATURE_ENET_QUEUE > 1 + case kENET_Ring1: + base->TDAR1 = ENET_TDAR1_TDAR_MASK; + break; + case kENET_Ring2: + base->TDAR2 = ENET_TDAR2_TDAR_MASK; + break; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + default: + base->TDAR = ENET_TDAR_TDAR_MASK; + break; + } +} + +/*! + * 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 + 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); + + uint32_t address; + + /* Get from physical address lower register. */ + address = base->PALR; + macAddr[0] = 0xFFU & (address >> 24U); + macAddr[1] = 0xFFU & (address >> 16U); + macAddr[2] = 0xFFU & (address >> 8U); + macAddr[3] = 0xFFU & address; + + /* Get from physical address high register. */ + address = (base->PAUR & ENET_PAUR_PADDR2_MASK) >> ENET_PAUR_PADDR2_SHIFT; + macAddr[4] = 0xFFU & (address >> 8U); + macAddr[5] = 0xFFU & 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. Normally it's the system clock. 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) +{ + assert(srcClock_Hz); + + uint32_t clkCycle = 0; + uint32_t speed = 0; + uint32_t mscr = 0; + + /* Calculate the MII speed which controls the frequency of the MDC. */ + speed = srcClock_Hz / (2 * ENET_MDC_FREQUENCY); + /* Calculate the hold time on the MDIO output. */ + clkCycle = (10 + ENET_NANOSECOND_ONE_SECOND / srcClock_Hz - 1) / (ENET_NANOSECOND_ONE_SECOND / srcClock_Hz) - 1; + /* Build the configuration for MDC/MDIO control. */ + mscr = + ENET_MSCR_MII_SPEED(speed) | ENET_MSCR_HOLDTIME(clkCycle) | (isPreambleDisabled ? ENET_MSCR_DIS_PRE_MASK : 0); + 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(1) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | ENET_MMFR_TA(2) | + (data & 0xFFFF); + 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(1) | ENET_MMFR_OP(operation) | ENET_MMFR_PA(phyAddr) | ENET_MMFR_RA(phyReg) | ENET_MMFR_TA(2); + 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 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. + * param data The data written to PHY. + */ +void ENET_StartExtC45SMIWrite(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 = (phyReg >> ENET_MMFR_TA_SHIFT) & 0x1FU; + uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU); + + /* Address write firstly. */ + 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; + + /* 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 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_StartExtC45SMIRead(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg) +{ + uint32_t mmfr = 0; + + /* Parse the address from the input register. */ + uint16_t devAddr = (phyReg >> ENET_MMFR_TA_SHIFT) & 0x1FU; + uint16_t regAddr = (uint16_t)(phyReg & 0xFFFFU); + + /* Address write firstly. */ + 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; + + /* 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 */ + +/*! + * brief Gets the error statistics of a received frame for ENET single 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); + * if (status == kStatus_ENET_RxFrameError) + * { + * // Get the error information of the received frame. + * ENET_GetRxErrBeforeReadFrame(&g_handle, &eErrStatic); + * // 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. + */ +void ENET_GetRxErrBeforeReadFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic) +{ + assert(handle); + assert(handle->rxBdCurrent[0]); + assert(eErrorStatic); + + uint16_t control = 0; + volatile enet_rx_bd_struct_t *curBuffDescrip = handle->rxBdCurrent[0]; + + do + { + /* The last buffer descriptor of a frame. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + control = curBuffDescrip->control; + if (control & ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK) + { + /* The receive truncate error. */ + eErrorStatic->statsRxTruncateErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK) + { + /* The receive over run error. */ + eErrorStatic->statsRxOverRunErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK) + { + /* The receive length violation error. */ + eErrorStatic->statsRxLenGreaterErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK) + { + /* The receive alignment error. */ + eErrorStatic->statsRxAlignErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_CRC_MASK) + { + /* The receive CRC error. */ + eErrorStatic->statsRxFcsErr++; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint16_t controlExt = curBuffDescrip->controlExtend1; + if (controlExt & ENET_BUFFDESCRIPTOR_RX_MACERR_MASK) + { + /* The MAC error. */ + eErrorStatic->statsRxMacErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK) + { + /* The PHY error. */ + eErrorStatic->statsRxPhyErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK) + { + /* The receive collision error. */ + eErrorStatic->statsRxCollisionErr++; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + break; + } + + /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) + { + curBuffDescrip = handle->rxBdBase[0]; + } + else + { + curBuffDescrip++; + } + + } while (curBuffDescrip != handle->rxBdCurrent[0]); +} + +/*! + * brief Gets the size of the read frame for single 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 update the + * receive buffers 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. + * 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) +{ + assert(handle); + assert(handle->rxBdCurrent[0]); + assert(length); + + /* Reset the length to zero. */ + *length = 0; + + uint16_t validLastMask = ENET_BUFFDESCRIPTOR_RX_LAST_MASK | ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + volatile enet_rx_bd_struct_t *curBuffDescrip = handle->rxBdCurrent[0]; + + /* Check the current buffer descriptor's empty flag. if empty means there is no frame received. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) + { + return kStatus_ENET_RxFrameEmpty; + } + + do + { + /* Add check for abnormal case. */ + if ((!(curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK)) && (!curBuffDescrip->length)) + { + return kStatus_ENET_RxFrameError; + } + + /* Find the last buffer descriptor. */ + if ((curBuffDescrip->control & validLastMask) == ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + /* The last buffer descriptor in the frame check the status of the received frame. */ + if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK) +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + || (curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK) +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + ) + { + return kStatus_ENET_RxFrameError; + } + /* FCS is removed by MAC. */ + *length = curBuffDescrip->length; + return kStatus_Success; + } + + /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) + { + curBuffDescrip = handle->rxBdBase[0]; + } + else + { + curBuffDescrip++; + } + } while (curBuffDescrip != handle->rxBdCurrent[0]); + + /* The frame is on processing - set to empty status to make application to receive it next time. */ + return kStatus_ENET_RxFrameEmpty; +} + +/*! + * brief Reads a frame from the ENET device for single ring. + * This function reads a frame (both the data and the length) from the ENET buffer descriptors. + * The ENET_GetRxFrameSize should be used to get the size of the prepared data buffer. + * This is an example: + * code + * uint32_t length; + * enet_handle_t g_handle; + * //Get the received frame size firstly. + * status = ENET_GetRxFrameSize(&g_handle, &length); + * if (length != 0) + * { + * //Allocate memory here with the size of "length" + * uint8_t *data = memory allocate interface; + * if (!data) + * { + * ENET_ReadFrame(ENET, &g_handle, NULL, 0); + * //Add the console warning log. + * } + * else + * { + * status = ENET_ReadFrame(ENET, &g_handle, data, length); + * //Call stack input API to deliver the data to stack + * } + * } + * else if (status == kStatus_ENET_RxFrameError) + * { + * //Update the received buffer when a error frame is received. + * ENET_ReadFrame(ENET, &g_handle, NULL, 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 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. + * return The execute status, successful or failure. + */ +status_t ENET_ReadFrame(ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length) +{ + assert(handle); + assert(handle->rxBdCurrent[0]); + + uint32_t len = 0; + uint32_t offset = 0; + uint16_t control; + bool isLastBuff = false; + volatile enet_rx_bd_struct_t *curBuffDescrip = handle->rxBdCurrent[0]; + status_t result = kStatus_Success; + uint32_t address; + + /* For data-NULL input, only update the buffer descriptor. */ + if (!data) + { + do + { + /* Update the control flag. */ + control = handle->rxBdCurrent[0]->control; + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, 0); + + /* Find the last buffer descriptor for the frame. */ + if (control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + break; + } + + } while (handle->rxBdCurrent[0] != curBuffDescrip); + + return result; + } + else + { + +/* 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 + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[0]); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + enet_ptp_time_data_t ptpTimestamp; + bool isPtpEventMessage = false; + /* Parse the PTP message according to the header message. */ + isPtpEventMessage = ENET_Ptp1588ParseFrame((uint8_t *)address, &ptpTimestamp, false); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + while (!isLastBuff) + { + /* The last buffer descriptor of a frame. */ + if (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; + memcpy(data + offset, (void *)address, len); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Store the PTP 1588 timestamp for received PTP event frame. */ + if (isPtpEventMessage) + { + /* Set the timestamp to the timestamp ring. */ + ptpTimestamp.timeStamp.nanosecond = curBuffDescrip->timestamp; + result = ENET_StoreRxFrameTime(base, handle, &ptpTimestamp); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, 0); + return result; + } + else + { + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, 0); + } + } + else + { + /* Store a frame on several buffer descriptors. */ + isLastBuff = false; + /* Length check. */ + if (offset >= length) + { + break; + } + + memcpy(data + offset, (void *)address, handle->rxBuffSizeAlign[0]); + offset += handle->rxBuffSizeAlign[0]; + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, 0); + } + + /* Get the current buffer descriptor. */ + curBuffDescrip = handle->rxBdCurrent[0]; + +/* Add the cache invalidate maintain. */ +#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 + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[0]); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + } + } + + return kStatus_ENET_RxFrameFail; +} + +static void ENET_UpdateReadBuffers(ENET_Type *base, enet_handle_t *handle, uint32_t ringId) +{ + assert(handle); + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + +// lw_print("lw: [%s] base %p handle %p ring %d\n", __func__, base, handle, ringId); + + /* Clears status. */ + handle->rxBdCurrent[ringId]->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK; + /* Sets the receive buffer descriptor with the empty flag. */ + handle->rxBdCurrent[ringId]->control |= ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + + /* Increase current buffer descriptor to the next one. */ + if (handle->rxBdCurrent[ringId]->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) + { + handle->rxBdCurrent[ringId] = handle->rxBdBase[ringId]; + } + else + { + handle->rxBdCurrent[ringId]++; + } + + /* 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: + base->RDAR = ENET_RDAR_RDAR_MASK; + break; + } +} + +/*! + * brief Transmits an ENET frame for single ring. + * 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_Init. + * param data The data buffer provided by user to be send. + * param length The length of the data to be send. + * 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) +{ + assert(handle); + assert(data); + + volatile enet_tx_bd_struct_t *curBuffDescrip; + uint32_t len = 0; + uint32_t sizeleft = 0; + uint32_t address; + + /* Check the frame length. */ + if (length > ENET_FRAME_MAX_FRAMELEN) + { + return kStatus_ENET_TxFrameOverLen; + } + + /* Check if the transmit buffer is ready. */ + curBuffDescrip = handle->txBdCurrent[0]; + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) + { + return kStatus_ENET_TxFrameBusy; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + bool isPtpEventMessage = false; + /* Check PTP message with the PTP header. */ + isPtpEventMessage = ENET_Ptp1588ParseFrame(data, NULL, true); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + +// lw_print("lw: [%s] size %d len %d\n", __func__, handle->txBuffSizeAlign[0], length); + + /* One transmit buffer is enough for one frame. */ + if (handle->txBuffSizeAlign[0] >= 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 */ + memcpy((void *)address, data, length); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + DCACHE_CleanByRange(address, length); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + /* Set data length. */ + curBuffDescrip->length = length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (isPtpEventMessage) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= ~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. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdCurrent[0] = handle->txBdBase[0]; + } + else + { + handle->txBdCurrent[0]++; + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, 0); + + return kStatus_Success; + } + else + { + /* One frame requires more than one transmit buffers. */ + do + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (isPtpEventMessage) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= ~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Increase the buffer descriptor address. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdCurrent[0] = handle->txBdBase[0]; + } + else + { + handle->txBdCurrent[0]++; + } + /* 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 */ + if (sizeleft > handle->txBuffSizeAlign[0]) + { + /* Data copy. */ + memcpy((void *)address, data + len, handle->txBuffSizeAlign[0]); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, handle->txBuffSizeAlign[0]); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + /* Data length update. */ + curBuffDescrip->length = handle->txBuffSizeAlign[0]; + len += handle->txBuffSizeAlign[0]; + /* Sets the control flag. */ + curBuffDescrip->control &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + /* Active the transmit buffer descriptor*/ + ENET_ActiveSend(base, 0); + } + else + { + memcpy((void *)address, data + len, sizeleft); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, sizeleft); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + curBuffDescrip->length = sizeleft; + /* Set Last buffer wrap flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, 0); + + return kStatus_Success; + } + + /* Get the current buffer descriptor address. */ + curBuffDescrip = handle->txBdCurrent[0]; + + } while (!(curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)); + + return kStatus_ENET_TxFrameBusy; + } +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief Gets the error statistics of received frame for extended multi-ring. + * + * This API must be called after the ENET_GetRxFrameSizeMultiRing and before the ENET_ReadFrameMultiRing(). + * If the ENET_GetRxFrameSizeMultiRing returns kStatus_ENET_RxFrameError, + * the ENET_GetRxErrBeforeReadFrameMultiRing can be used to get the exact error statistics. + * + * 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_QUEUE - 1. + */ +void ENET_GetRxErrBeforeReadFrameMultiRing(enet_handle_t *handle, + enet_data_error_stats_t *eErrorStatic, + uint32_t ringId) +{ + assert(handle); + assert(eErrorStatic); + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + uint16_t control = 0; + volatile enet_rx_bd_struct_t *curBuffDescrip = handle->rxBdCurrent[ringId]; + + do + { + /* The last buffer descriptor of a frame. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + control = curBuffDescrip->control; + if (control & ENET_BUFFDESCRIPTOR_RX_TRUNC_MASK) + { + /* The receive truncate error. */ + eErrorStatic->statsRxTruncateErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_OVERRUN_MASK) + { + /* The receive over run error. */ + eErrorStatic->statsRxOverRunErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_LENVLIOLATE_MASK) + { + /* The receive length violation error. */ + eErrorStatic->statsRxLenGreaterErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_NOOCTET_MASK) + { + /* The receive alignment error. */ + eErrorStatic->statsRxAlignErr++; + } + if (control & ENET_BUFFDESCRIPTOR_RX_CRC_MASK) + { + /* The receive CRC error. */ + eErrorStatic->statsRxFcsErr++; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + uint16_t controlExt = curBuffDescrip->controlExtend1; + if (controlExt & ENET_BUFFDESCRIPTOR_RX_MACERR_MASK) + { + /* The MAC error. */ + eErrorStatic->statsRxMacErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_RX_PHYERR_MASK) + { + /* The PHY error. */ + eErrorStatic->statsRxPhyErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_RX_COLLISION_MASK) + { + /* The receive collision error. */ + eErrorStatic->statsRxCollisionErr++; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + break; + } + + /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) + { + curBuffDescrip = handle->rxBdBase[ringId]; + } + else + { + curBuffDescrip++; + } + + } while (curBuffDescrip != handle->rxBdCurrent[ringId]); +} + +/*! + * brief Gets the size of the read frame for extended mutli-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_GetRxFrameSizeMultiRing, ENET_ReadFrameMultiRing() should be called to update the + * receive buffers If the result is not "kStatus_ENET_RxFrameEmpty". The usage is + * the same to the single ring, refer to ENET_GetRxFrameSize. + * + * 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_ReadFrameMultiRing to read frame. + * retval kStatus_ENET_RxFrameError Data error happens. ENET_ReadFrameMultiRing 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_GetRxFrameSizeMultiRing(enet_handle_t *handle, uint32_t *length, uint32_t ringId) +{ + assert(handle); + assert(length); + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + /* Reset the length to zero. */ + *length = 0; + uint16_t validLastMask = ENET_BUFFDESCRIPTOR_RX_LAST_MASK | ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK; + volatile enet_rx_bd_struct_t *curBuffDescrip; + + curBuffDescrip = handle->rxBdCurrent[ringId]; + /* Check the current buffer descriptor's empty flag. if empty means there is no frame received. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) + { + return kStatus_ENET_RxFrameEmpty; + } + + do + { + /* Add check for abnormal case. */ + if ((!(curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK)) && (!curBuffDescrip->length)) + { + return kStatus_ENET_RxFrameError; + } + /* Find the last buffer descriptor. */ + if ((curBuffDescrip->control & validLastMask) == ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + /* The last buffer descriptor in the frame check the status of the received frame. */ + if ((curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_ERR_MASK) +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + || (curBuffDescrip->controlExtend1 & ENET_BUFFDESCRIPTOR_RX_EXT_ERR_MASK) +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + ) + { + return kStatus_ENET_RxFrameError; + } + /* FCS is removed by MAC. */ + *length = curBuffDescrip->length; + return kStatus_Success; + } + /* Increase the buffer descriptor, if it is the last one, increase to first one of the ring buffer. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_RX_WRAP_MASK) + { + curBuffDescrip = handle->rxBdBase[ringId]; + } + else + { + curBuffDescrip++; + } + } while (curBuffDescrip != handle->rxBdCurrent[ringId]); + + /* The frame is on processing - set to empty status to make application to receive it next time. */ + return kStatus_ENET_RxFrameEmpty; +} + +/*! + * brief Reads a frame from the ENET device for multi-ring. + * + * This function reads a frame (both the data and the length) from the ENET buffer descriptors. + * The ENET_GetRxFrameSizeMultiRing should be used to get the size of the prepared data buffer. + * This usage is the same as the single ring, refer to ENET_ReadFrame. + + * 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; + * return The execute status, successful or failure. + */ +status_t ENET_ReadFrameMultiRing( + ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint32_t ringId) +{ + assert(handle); + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + uint32_t len = 0; + uint32_t offset = 0; + uint16_t control; + bool isLastBuff = false; + volatile enet_rx_bd_struct_t *curBuffDescrip = handle->rxBdCurrent[ringId]; + status_t result = kStatus_Success; + uint32_t address; + + /* For data-NULL input, only update the buffer descriptor. */ + if (!data) + { + do + { + /* Update the control flag. */ + control = handle->rxBdCurrent[ringId]->control; + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + + /* Find the last buffer descriptor for the frame. */ + if (control & ENET_BUFFDESCRIPTOR_RX_LAST_MASK) + { + break; + } + + } while (handle->rxBdCurrent[ringId] != curBuffDescrip); + + return result; + } + else + { +/* 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 + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + enet_ptp_time_data_t ptpTimestamp; + bool isPtpEventMessage = false; + /* Parse the PTP message according to the header message. */ + isPtpEventMessage = ENET_Ptp1588ParseFrame((uint8_t *)address, &ptpTimestamp, false); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + while (!isLastBuff) + { + /* The last buffer descriptor of a frame. */ + if (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; + memcpy(data + offset, (void *)address, len); +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* Store the PTP 1588 timestamp for received PTP event frame. */ + if (isPtpEventMessage) + { + /* Set the timestamp to the timestamp ring. */ + ptpTimestamp.timeStamp.nanosecond = curBuffDescrip->timestamp; + result = ENET_StoreRxFrameTime(base, handle, &ptpTimestamp); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + return result; + } + 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) + { + break; + } + memcpy(data + offset, (void *)address, handle->rxBuffSizeAlign[ringId]); + offset += handle->rxBuffSizeAlign[ringId]; + + /* Updates the receive buffer descriptors. */ + ENET_UpdateReadBuffers(base, handle, ringId); + } + + /* Get the current buffer descriptor. */ + + curBuffDescrip = handle->rxBdCurrent[ringId]; +#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 + /* Add the cache invalidate maintain. */ + DCACHE_InvalidateByRange(address, handle->rxBuffSizeAlign[ringId]); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + } + } + + return kStatus_ENET_RxFrameFail; +} + +/*! + * brief Transmits an ENET frame for extended multi-ring. + * note The CRC is automatically appended to the data. Input the data + * to send without the CRC. + * + * In this API, multiple-ring are mainly used for extended avb frames are supported. + * The transmit scheme for avb frames is the credit-based scheme, the AVB class A, AVB class B + * and the non-AVB frame are transmitted in ring 1, ring 2 and ring 0 independently. + * So application should care about the transmit ring index when use multiple-ring 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 data The data buffer provided by user to be send. + * param length The length of the data to be send. + * param ringId The ring index for transmission. + * 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_SendFrameMultiRing( + ENET_Type *base, enet_handle_t *handle, uint8_t *data, uint32_t length, uint32_t ringId) +{ + assert(handle); + assert(data); + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + volatile enet_tx_bd_struct_t *curBuffDescrip; + uint32_t len = 0; + uint32_t sizeleft = 0; + uint32_t address; + + /* Check the frame length. */ + if (length > ENET_FRAME_MAX_FRAMELEN) + { + return kStatus_ENET_TxFrameOverLen; + } + + /* Check if the transmit buffer is ready. */ + curBuffDescrip = handle->txBdCurrent[ringId]; + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) + { + return kStatus_ENET_TxFrameBusy; + } +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + bool isPtpEventMessage = false; + /* Check PTP message with the PTP header. */ + isPtpEventMessage = ENET_Ptp1588ParseFrame(data, NULL, true); +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + /* 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 */ + memcpy((void *)address, data, length); + +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, length); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + + /* Set data length. */ + curBuffDescrip->length = length; +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (isPtpEventMessage) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= ~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. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdCurrent[ringId] = handle->txBdBase[ringId]; + } + else + { + handle->txBdCurrent[ringId]++; + } + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, ringId); + + return kStatus_Success; + } + else + { + /* One frame requires more than one transmit buffers. */ + do + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + /* For enable the timestamp. */ + if (isPtpEventMessage) + { + curBuffDescrip->controlExtend1 |= ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } + else + { + curBuffDescrip->controlExtend1 &= ~ENET_BUFFDESCRIPTOR_TX_TIMESTAMP_MASK; + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Increase the buffer descriptor address. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdCurrent[ringId] = handle->txBdBase[ringId]; + } + else + { + handle->txBdCurrent[ringId]++; + } + /* 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 */ + if (sizeleft > handle->txBuffSizeAlign[ringId]) + { + /* Data copy. */ + memcpy((void *)address, data + len, handle->txBuffSizeAlign[ringId]); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + /* 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. */ + curBuffDescrip->control &= ~ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK; + + /* Active the transmit buffer descriptor*/ + ENET_ActiveSend(base, ringId); + } + else + { + memcpy((void *)address, data + len, sizeleft); +#if defined(FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL) && FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL + /* Add the cache clean maintain. */ + DCACHE_CleanByRange(address, sizeleft); +#endif /* FSL_SDK_ENABLE_DRIVER_CACHE_CONTROL */ + curBuffDescrip->length = sizeleft; + /* Set Last buffer wrap flag. */ + curBuffDescrip->control |= ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK; + + /* Active the transmit buffer descriptor. */ + ENET_ActiveSend(base, ringId); + + return kStatus_Success; + } + + /* Get the current buffer descriptor address. */ + curBuffDescrip = handle->txBdCurrent[ringId]; + } while (!(curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK)); + + return kStatus_ENET_TxFrameBusy; + } +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +/*! + * 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); + + 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 < ENET_FRAME_MACLEN; count1++) + { + uint8_t c = address[count1]; + for (count2 = 0; count2 < 0x08U; count2++) + { + if ((c ^ crc) & 1U) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xEDB88320U; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + /* Enable a multicast group address. */ + if (!((crc >> 0x1FU) & 1U)) + { + base->GALR |= 1U << ((crc >> 0x1AU) & 0x1FU); + } + else + { + base->GAUR |= 1U << ((crc >> 0x1AU) & 0x1FU); + } +} + +/*! + * 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); + + 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 < ENET_FRAME_MACLEN; count1++) + { + uint8_t c = address[count1]; + for (count2 = 0; count2 < 0x08U; count2++) + { + if ((c ^ crc) & 1U) + { + crc >>= 1U; + c >>= 1U; + crc ^= 0xEDB88320U; + } + else + { + crc >>= 1U; + c >>= 1U; + } + } + } + + /* Set the hash table. */ + if (!((crc >> 0x1FU) & 1U)) + { + base->GALR &= ~(1U << ((crc >> 0x1AU) & 0x1FU)); + } + else + { + base->GAUR &= ~(1U << ((crc >> 0x1AU) & 0x1FU)); + } +} + +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE +/*! + * brief Gets the ENET transmit frame statistics after the data send for single 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. + * return The execute status. + */ +status_t ENET_GetTxErrAfterSendFrame(enet_handle_t *handle, enet_data_error_stats_t *eErrorStatic) +{ + assert(handle); + assert(eErrorStatic); + + uint16_t control = 0; + uint16_t controlExt = 0; + + do + { + /* Get the current dirty transmit buffer descriptor. */ + control = handle->txBdDirtyStatic[0]->control; + controlExt = handle->txBdDirtyStatic[0]->controlExtend0; + + /* Get the control status data, If the buffer descriptor has not been processed break out. */ + if (control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) + { + return kStatus_ENET_TxFrameBusy; + } + /* Increase the transmit dirty static pointer. */ + if (handle->txBdDirtyStatic[0]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdDirtyStatic[0] = handle->txBdBase[0]; + } + else + { + handle->txBdDirtyStatic[0]++; + } + + /* If the transmit buffer descriptor is ready and the last buffer descriptor, store packet statistic. */ + if (control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK) + { + if (controlExt & ENET_BUFFDESCRIPTOR_TX_ERR_MASK) + { + /* Transmit error. */ + eErrorStatic->statsTxErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK) + { + /* Transmit excess collision error. */ + eErrorStatic->statsTxExcessCollisionErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK) + { + /* Transmit late collision error. */ + eErrorStatic->statsTxLateCollisionErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK) + { + /* Transmit under flow error. */ + eErrorStatic->statsTxUnderFlowErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK) + { + /* Transmit over flow error. */ + eErrorStatic->statsTxOverFlowErr++; + } + return kStatus_Success; + } + + } while (handle->txBdDirtyStatic[0] != handle->txBdCurrent[0]); + + return kStatus_ENET_TxFrameFail; +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * brief Gets the ENET transmit frame statistics after the data send for extended multi-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 and shall be called by 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. + * return The execute status. + */ +status_t ENET_GetTxErrAfterSendFrameMultiRing(enet_handle_t *handle, + enet_data_error_stats_t *eErrorStatic, + uint32_t ringId) +{ + assert(handle); + assert(eErrorStatic); + assert(ringId < FSL_FEATURE_ENET_QUEUE); + + uint16_t control = 0; + uint16_t controlExt = 0; + + 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 (control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) + { + return kStatus_ENET_TxFrameBusy; + } + /* Increase the transmit dirty static pointer. */ + if (handle->txBdDirtyStatic[ringId]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdDirtyStatic[ringId] = handle->txBdBase[ringId]; + } + else + { + handle->txBdDirtyStatic[ringId]++; + } + + /* If the transmit buffer descriptor is ready and the last buffer descriptor, store packet statistic. */ + if (control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK) + { + if (controlExt & ENET_BUFFDESCRIPTOR_TX_ERR_MASK) + { + /* Transmit error. */ + eErrorStatic->statsTxErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_EXCCOLLISIONERR_MASK) + { + /* Transmit excess collision error. */ + eErrorStatic->statsTxExcessCollisionErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_LATECOLLISIONERR_MASK) + { + /* Transmit late collision error. */ + eErrorStatic->statsTxLateCollisionErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_UNDERFLOWERR_MASK) + { + /* Transmit under flow error. */ + eErrorStatic->statsTxUnderFlowErr++; + } + if (controlExt & ENET_BUFFDESCRIPTOR_TX_OVERFLOWERR_MASK) + { + /* Transmit over flow error. */ + eErrorStatic->statsTxOverFlowErr++; + } + return kStatus_Success; + } + + } while (handle->txBdDirtyStatic[ringId] != handle->txBdCurrent[ringId]); + + return kStatus_ENET_TxFrameFail; +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +static bool ENET_Ptp1588ParseFrame(const uint8_t *data, enet_ptp_time_data_t *ptpTsData, bool isFastEnabled) +{ + assert(data); + if (!isFastEnabled) + { + assert(ptpTsData); + } + + bool isPtpMsg = false; + const uint8_t *buffer = data; + uint16_t ptpType; + + /* Check for VLAN frame. + * Add Double vlan tag check for receiving extended QIN vlan frame. */ + if (*(uint16_t *)(buffer + ENET_PTP1588_ETHL2_PACKETTYPE_OFFSET) == (ENET_HTONS(ENET_8021QVLAN) +#if defined(FSL_FEATUR_ENET_HAS_AVB) && FSL_FEATURE_HAS_AVB + || ENET_HTONS(ENET_8021QSVLAN) +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + )) + { + buffer += ENET_FRAME_VLAN_TAGLEN; +#if defined(FSL_FEATUR_ENET_HAS_AVB) && FSL_FEATURE_HAS_AVB + if (*(uint16_t *)(buffer + ENET_PTP1588_ETHL2_PACKETTYPE_OFFSET) == ENET_HTONS(ENET_8021QVLAN) + { + buffer += ENET_FRAME_VLAN_TAGLEN; + } +#endif /* FSL_FEATURE_ENET_HAS_AVB */ + } + + ptpType = *(uint16_t *)(buffer + ENET_PTP1588_ETHL2_PACKETTYPE_OFFSET); + switch (ENET_HTONS(ptpType)) + { /* Ethernet layer 2. */ + case ENET_ETHERNETL2: + if ((*(uint8_t *)(buffer + ENET_PTP1588_ETHL2_MSGTYPE_OFFSET) & 0x0F) <= kENET_PtpEventMsgType) + { + isPtpMsg = true; + if (!isFastEnabled) + { + /* It's a ptpv2 message and store the ptp header information. */ + ptpTsData->version = (*(uint8_t *)(buffer + ENET_PTP1588_ETHL2_VERSION_OFFSET)) & 0x0F; + ptpTsData->messageType = (*(uint8_t *)(buffer + ENET_PTP1588_ETHL2_MSGTYPE_OFFSET)) & 0x0F; + ptpTsData->sequenceId = ENET_HTONS(*(uint16_t *)(buffer + ENET_PTP1588_ETHL2_SEQUENCEID_OFFSET)); + memcpy((void *)&ptpTsData->sourcePortId[0], (void *)(buffer + ENET_PTP1588_ETHL2_CLOCKID_OFFSET), + kENET_PtpSrcPortIdLen); + } + } + break; + /* IPV4. */ + case ENET_IPV4: + if ((*(uint8_t *)(buffer + ENET_PTP1588_IPVERSION_OFFSET) >> 4) == ENET_IPV4VERSION) + { + if (((*(uint16_t *)(buffer + ENET_PTP1588_IPV4_UDP_PORT_OFFSET)) == ENET_HTONS(kENET_PtpEventPort)) && + (*(uint8_t *)(buffer + ENET_PTP1588_IPV4_UDP_PROTOCOL_OFFSET) == ENET_UDPVERSION)) + { + /* Set the PTP message flag. */ + isPtpMsg = true; + if (!isFastEnabled) + { + /* It's a IPV4 ptp message and store the ptp header information. */ + ptpTsData->version = (*(uint8_t *)(buffer + ENET_PTP1588_IPV4_UDP_VERSION_OFFSET)) & 0x0F; + ptpTsData->messageType = (*(uint8_t *)(buffer + ENET_PTP1588_IPV4_UDP_MSGTYPE_OFFSET)) & 0x0F; + ptpTsData->sequenceId = + ENET_HTONS(*(uint16_t *)(buffer + ENET_PTP1588_IPV4_UDP_SEQUENCEID_OFFSET)); + memcpy((void *)&ptpTsData->sourcePortId[0], + (void *)(buffer + ENET_PTP1588_IPV4_UDP_CLKID_OFFSET), kENET_PtpSrcPortIdLen); + } + } + } + break; + /* IPV6. */ + case ENET_IPV6: + if ((*(uint8_t *)(buffer + ENET_PTP1588_IPVERSION_OFFSET) >> 4) == ENET_IPV6VERSION) + { + if (((*(uint16_t *)(buffer + ENET_PTP1588_IPV6_UDP_PORT_OFFSET)) == ENET_HTONS(kENET_PtpEventPort)) && + (*(uint8_t *)(buffer + ENET_PTP1588_IPV6_UDP_PROTOCOL_OFFSET) == ENET_UDPVERSION)) + { + /* Set the PTP message flag. */ + isPtpMsg = true; + if (!isFastEnabled) + { + /* It's a IPV6 ptp message and store the ptp header information. */ + ptpTsData->version = (*(uint8_t *)(buffer + ENET_PTP1588_IPV6_UDP_VERSION_OFFSET)) & 0x0F; + ptpTsData->messageType = (*(uint8_t *)(buffer + ENET_PTP1588_IPV6_UDP_MSGTYPE_OFFSET)) & 0x0F; + ptpTsData->sequenceId = + ENET_HTONS(*(uint16_t *)(buffer + ENET_PTP1588_IPV6_UDP_SEQUENCEID_OFFSET)); + memcpy((void *)&ptpTsData->sourcePortId[0], + (void *)(buffer + ENET_PTP1588_IPV6_UDP_CLKID_OFFSET), kENET_PtpSrcPortIdLen); + } + } + } + break; + default: + break; + } + return isPtpMsg; +} + +/*! + * 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); + assert(ptpConfig); + uint8_t count; + + uint32_t instance = ENET_GetInstance(base); + uint32_t mask = kENET_TxBufferInterrupt; +#if FSL_FEATURE_ENET_QUEUE > 1 + mask |= kENET_TxBuffer1Interrupt | kENET_TxBuffer2Interrupt; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + /* Start the 1588 timer. */ + ENET_Ptp1588StartTimer(base, ptpConfig->ptp1588ClockSrc_Hz); + + for (count = 0; count < handle->ringNum; count++) + { + handle->txBdDirtyTime[count] = handle->txBdBase[count]; + handle->txBdDirtyStatic[count] = handle->txBdBase[count]; + } + + /* Setting the receive and transmit state for transaction. */ + handle->rxPtpTsDataRing.ptpTsData = ptpConfig->rxPtpTsData; + handle->rxPtpTsDataRing.size = ptpConfig->ptpTsRxBuffNum; + handle->rxPtpTsDataRing.front = 0; + handle->rxPtpTsDataRing.end = 0; + handle->txPtpTsDataRing.ptpTsData = ptpConfig->txPtpTsData; + handle->txPtpTsDataRing.size = ptpConfig->ptpTsTxBuffNum; + handle->txPtpTsDataRing.front = 0; + handle->txPtpTsDataRing.end = 0; + handle->msTimerSecond = 0; + + /* Set the IRQ handler when the interrupt is enabled. */ + s_enetTxIsr = ENET_TransmitIRQHandler; + s_enetTsIsr = ENET_Ptp1588TimerIRQHandler; + + /* Enables the time stamp interrupt and transmit frame interrupt to + * handle the time-stamp . */ + ENET_EnableInterrupts(base, (ENET_TS_INTERRUPT | ENET_TX_INTERRUPT)); + ENET_DisableInterrupts(base, mask); + + EnableIRQ(s_enetTsIrqId[instance]); + EnableIRQ(s_enetTxIrqId[instance]); +} + +/*! + * 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. + * + * 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); + assert(ptpTime); + uint16_t count = ENET_1588TIME_DELAY_COUNT; + uint32_t primask; + + /* Disables the interrupt. */ + primask = DisableGlobalIRQ(); + + /* Get the current PTP time. */ + ptpTime->second = handle->msTimerSecond; + /* Get the nanosecond from the master timer. */ + base->ATCR |= ENET_ATCR_CAPTURE_MASK; + /* Add at least six clock cycle delay to get accurate time. + It's the requirement when the 1588 clock source is slower + than the register clock. + */ + while (count--) + { + __NOP(); + } + /* Get the captured time. */ + ptpTime->nanosecond = base->ATVR; + + /* Get PTP timer wrap event. */ + if (base->EIR & 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); + assert(ptpTime); + + 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); +} + +static status_t ENET_Ptp1588UpdateTimeRing(enet_ptp_time_data_ring_t *ptpTsDataRing, enet_ptp_time_data_t *ptpTimeData) +{ + assert(ptpTsDataRing); + assert(ptpTsDataRing->ptpTsData); + assert(ptpTimeData); + + uint16_t usedBuffer = 0; + + /* Check if the buffers ring is full. */ + if (ptpTsDataRing->end >= ptpTsDataRing->front) + { + usedBuffer = ptpTsDataRing->end - ptpTsDataRing->front; + } + else + { + usedBuffer = ptpTsDataRing->size - (ptpTsDataRing->front - ptpTsDataRing->end); + } + + if (usedBuffer == (ptpTsDataRing->size - 1)) + { + /* Ptp timestamp ring full, drop one in the front. */ + ptpTsDataRing->front = (ptpTsDataRing->front + 1) % ptpTsDataRing->size; + } + + /* Copy the new data into the buffer. */ + memcpy((ptpTsDataRing->ptpTsData + ptpTsDataRing->end), ptpTimeData, sizeof(enet_ptp_time_data_t)); + + /* Increase the buffer pointer to the next empty one. */ + ptpTsDataRing->end = (ptpTsDataRing->end + 1) % ptpTsDataRing->size; + + return kStatus_Success; +} + +static status_t ENET_Ptp1588SearchTimeRing(enet_ptp_time_data_ring_t *ptpTsDataRing, enet_ptp_time_data_t *ptpTimedata) +{ + assert(ptpTsDataRing); + assert(ptpTsDataRing->ptpTsData); + assert(ptpTimedata); + + uint32_t index; + uint32_t size; + uint16_t usedBuffer = 0; + bool isRingBufferFull = false; + + /* Check the PTP 1588 timestamp ring. */ + if (ptpTsDataRing->front == ptpTsDataRing->end) + { + return kStatus_ENET_PtpTsRingEmpty; + } + + /* Check if buffers is full. */ + if (ptpTsDataRing->end >= ptpTsDataRing->front) + { + usedBuffer = ptpTsDataRing->end - ptpTsDataRing->front; + } + else + { + usedBuffer = ptpTsDataRing->size - (ptpTsDataRing->front - ptpTsDataRing->end); + } + + if (usedBuffer == (ptpTsDataRing->size-1)) + { + isRingBufferFull = true; + } + + /* Search the element in the ring buffer */ + index = ptpTsDataRing->front; + size = ptpTsDataRing->size; + while (index != ptpTsDataRing->end) + { + if (((ptpTsDataRing->ptpTsData + index)->sequenceId == ptpTimedata->sequenceId) && + (!memcmp(((void *)&(ptpTsDataRing->ptpTsData + index)->sourcePortId[0]), + (void *)&ptpTimedata->sourcePortId[0], kENET_PtpSrcPortIdLen)) && + ((ptpTsDataRing->ptpTsData + index)->version == ptpTimedata->version) && + ((ptpTsDataRing->ptpTsData + index)->messageType == ptpTimedata->messageType)) + { + break; + } + + /* Increase the ptp ring index. */ + index = (index + 1) % size; + } + + if (index == ptpTsDataRing->end) + { + if (isRingBufferFull == true) + { + /* PTP timestamp buffer ring full, data in index ptpTsDataRing->end is valid. */ + if (((ptpTsDataRing->ptpTsData + index)->sequenceId != ptpTimedata->sequenceId) || + (memcmp(((void *)&(ptpTsDataRing->ptpTsData + index)->sourcePortId[0]), + (void *)&ptpTimedata->sourcePortId[0], kENET_PtpSrcPortIdLen)) || + ((ptpTsDataRing->ptpTsData + index)->version != ptpTimedata->version) || + ((ptpTsDataRing->ptpTsData + index)->messageType != ptpTimedata->messageType)) + { + return kStatus_ENET_PtpTsRingFull; + } + } + else + { + return kStatus_ENET_PtpTsRingFull; + } + } + + /* Get the right timestamp of the required ptp messag. */ + ptpTimedata->timeStamp.second = (ptpTsDataRing->ptpTsData + index)->timeStamp.second; + ptpTimedata->timeStamp.nanosecond = (ptpTsDataRing->ptpTsData + index)->timeStamp.nanosecond; + + if( isRingBufferFull == true) + { + /* If ring buffer full, move front pointer to next pointer behind end pointer, then next + read will still read whole ring. */ + ptpTsDataRing->end = index; + } + + /* Drop previous ptp stamp. */ + ptpTsDataRing->front = (index + 1) % size; + + return kStatus_Success; +} + +static status_t ENET_StoreRxFrameTime(ENET_Type *base, enet_handle_t *handle, enet_ptp_time_data_t *ptpTimeData) +{ + assert(handle); + assert(ptpTimeData); + + enet_ptp_time_t ptpTimer; + + /* Get current PTP timer nanosecond value. */ + ENET_Ptp1588GetTimer(base, handle, &ptpTimer); + + /* Get transmit time stamp second. */ + if (ptpTimer.nanosecond >= ptpTimeData->timeStamp.nanosecond) + { + ptpTimeData->timeStamp.second = ptpTimer.second; + } + else + { + ptpTimeData->timeStamp.second = ptpTimer.second - 1; + } + + /* Store the timestamp to the receive time stamp ring. */ + /* Check if the buffers ring is full. */ + return ENET_Ptp1588UpdateTimeRing(&handle->rxPtpTsDataRing, ptpTimeData); +} + +static status_t ENET_StoreTxFrameTime(ENET_Type *base, enet_handle_t *handle, uint32_t ringId) +{ + assert(handle); + + bool isPtpEventMessage = false; + enet_ptp_time_data_t ptpTimeData; + volatile enet_tx_bd_struct_t *curBuffDescrip; + volatile enet_tx_bd_struct_t *endBuffDescrip; + uint32_t address; + bool isReadLastBd = false; + bool readLastBd = false; + + /* Treat the txBdCurrent[ringId] as the tx bd write buffer pointer, + txBdDirtyTime[ringId] as the tx bd read buffer pointer. Considering + that the tx frame time read is driven by tx frame send, so the read + pointer txBdDirtyTime[ringId] should always behind write pointer + txBdDirtyTime[ringId]. Then if the read pointer equals write pointer, + we could treat the tx bd buffer is full. We could read out all + available bds. */ + if(handle->txBdDirtyTime[ringId] == handle->txBdCurrent[ringId]) + { + isReadLastBd = true; + if(handle->txBdDirtyTime[ringId] == handle->txBdBase[ringId]) + { + endBuffDescrip = handle->txBdDirtyTime[ringId] + 3; + } + else + { + endBuffDescrip = handle->txBdDirtyTime[ringId] - 1; + } + } + else + { + endBuffDescrip = handle->txBdCurrent[ringId]; + } + + /* Read tx bd buffer until read pointer txBdDirtyTime[ringId] equals to the end pointer of + tx bd buffer. */ + while((handle->txBdDirtyTime[ringId] != endBuffDescrip) || (readLastBd == true)) + { + curBuffDescrip = handle->txBdDirtyTime[ringId]; + + /* Get the control status data, If the buffer descriptor has not been processed break out. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_READY_MASK) + { + return kStatus_ENET_TxFrameBusy; + } + + /* Parse the PTP message. */ + #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 */ + isPtpEventMessage = ENET_Ptp1588ParseFrame((uint8_t *)address, &ptpTimeData, false); + if (isPtpEventMessage) + { + /* Only store tx timestamp for ptp event message. */ + /* Increase current buffer descriptor to the next one. */ + if (handle->txBdDirtyTime[ringId]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdDirtyTime[ringId] = handle->txBdBase[ringId]; + } + else + { + handle->txBdDirtyTime[ringId]++; + } + + /* Do time stamp check on the last buffer descriptor of the frame. */ + if (curBuffDescrip->control & ENET_BUFFDESCRIPTOR_TX_LAST_MASK) + { + /* Get current PTP timer nanosecond value. */ + ENET_Ptp1588GetTimer(base, handle, &ptpTimeData.timeStamp); + + /* Get transmit time stamp second. */ + if (ptpTimeData.timeStamp.nanosecond < curBuffDescrip->timestamp) + { + ptpTimeData.timeStamp.second--; + } + + /* Save transmit time stamp nanosecond. */ + ptpTimeData.timeStamp.nanosecond = curBuffDescrip->timestamp; + + /* Store the timestamp to the transmit timestamp ring. */ + ENET_Ptp1588UpdateTimeRing(&handle->txPtpTsDataRing, &ptpTimeData); + } + } + else + { + /* Only increase current buffer descriptor to the next one. */ + if (handle->txBdDirtyTime[ringId]->control & ENET_BUFFDESCRIPTOR_TX_WRAP_MASK) + { + handle->txBdDirtyTime[ringId] = handle->txBdBase[ringId]; + } + else + { + handle->txBdDirtyTime[ringId]++; + } + } + + if(readLastBd == true) + { + break; + } + + /* If if read pointer equals write pointer, the end pointer is set at the pointer before + current write pointer and the buffer in the end pointer is available, so read last bd at + the end pointer. */ + if((isReadLastBd == true) && (handle->txBdDirtyTime[ringId] == endBuffDescrip)) + { + readLastBd = true; + } + } + return kStatus_Success; +} + +/*! + * 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_Init. + * param ptpTimeData The special PTP timestamp data for search the receive timestamp. + * retval kStatus_Success Get 1588 timestamp success. + * retval kStatus_ENET_PtpTsRingEmpty 1588 timestamp ring empty. + * retval kStatus_ENET_PtpTsRingFull 1588 timestamp ring full. + */ +status_t ENET_GetTxFrameTime(enet_handle_t *handle, enet_ptp_time_data_t *ptpTimeData) +{ + assert(handle); + assert(ptpTimeData); + + return ENET_Ptp1588SearchTimeRing(&handle->txPtpTsDataRing, ptpTimeData); +} + +/*! + * brief Gets the time stamp of the received 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_Init. + * param ptpTimeData The special PTP timestamp data for search the receive timestamp. + * retval kStatus_Success Get 1588 timestamp success. + * retval kStatus_ENET_PtpTsRingEmpty 1588 timestamp ring empty. + * retval kStatus_ENET_PtpTsRingFull 1588 timestamp ring full. + */ +status_t ENET_GetRxFrameTime(enet_handle_t *handle, enet_ptp_time_data_t *ptpTimeData) +{ + assert(handle); + assert(ptpTimeData); + + return ENET_Ptp1588SearchTimeRing(&handle->rxPtpTsDataRing, ptpTimeData); +} + +#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); + + uint8_t count = 0; + + for (count = 0; count < FSL_FEATURE_ENET_QUEUE - 1; count++) + { + /* Set the AVB receive ring classification match when the match is not 0. */ + if (config->rxClassifyMatch[count]) + { + base->RCMR[count] = (config->rxClassifyMatch[count] & 0xFFFF) | 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_FETAURE_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); + uint32_t mask = kENET_TxBufferInterrupt | kENET_TxFrameInterrupt; +#if defined(ENET_ENHANCEDBUFFERDESCRIPTOR_MODE) || (FSL_FEATURE_ENET_QUEUE > 1) + uint32_t index = 0; +#endif /* ENET_ENHANCEDBUFFERDESCRIPTORMODE || (FSL_FEATURE_ENET_QUEUE > 1) */ + +/* Check if the transmit interrupt happen. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + switch (ringId) + { + case kENET_Ring1: + mask = (kENET_TxFrame1Interrupt | kENET_TxBuffer1Interrupt); + break; + case kENET_Ring2: + mask = (kENET_TxFrame2Interrupt | kENET_TxBuffer2Interrupt); + break; + default: + break; + } + index = ringId; +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + while (mask & base->EIR) + { +#ifdef ENET_ENHANCEDBUFFERDESCRIPTOR_MODE + if (base->EIR & kENET_TxFrameInterrupt) + { + /* Store the transmit timestamp from the buffer descriptor should be done here. */ + ENET_StoreTxFrameTime(base, handle, index); + } +#endif /* ENET_ENHANCEDBUFFERDESCRIPTOR_MODE */ + + /* Clear the transmit interrupt event. */ + base->EIR = mask; + + /* Callback function. */ + if (handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, index, kENET_TxEvent, handle->userData); +#else + handle->callback(base, handle, kENET_TxEvent, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } +} + +#if FSL_FEATURE_ENET_QUEUE > 1 +/*! + * 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, uint32_t ringId) +#else +/*! + * 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 */ +{ + assert(handle); + uint32_t mask = kENET_RxFrameInterrupt | kENET_RxBufferInterrupt; + +/* Check if the receive interrupt happen. */ +#if FSL_FEATURE_ENET_QUEUE > 1 + switch (ringId) + { + case kENET_Ring1: + mask = (kENET_RxFrame1Interrupt | kENET_RxBuffer1Interrupt); + break; + case kENET_Ring2: + mask = (kENET_RxFrame2Interrupt | kENET_RxBuffer2Interrupt); + break; + default: + break; + } +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + + while (mask & base->EIR) + { + /* Clear the transmit interrupt event. */ + base->EIR = mask; + + /* Callback function. */ + if (handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, ringId, kENET_RxEvent, handle->userData); +#else + handle->callback(base, handle, kENET_RxEvent, 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); + + uint32_t errMask = kENET_BabrInterrupt | kENET_BabtInterrupt | kENET_EBusERInterrupt | kENET_PayloadRxInterrupt | + kENET_LateCollisionInterrupt | kENET_RetryLimitInterrupt | kENET_UnderrunInterrupt; + + /* Check if the error interrupt happen. */ + if (kENET_WakeupInterrupt & base->EIR) + { + /* Clear the wakeup interrupt. */ + base->EIR = kENET_WakeupInterrupt; + /* wake up and enter the normal mode. */ + ENET_EnableSleepMode(base, false); + /* Callback function. */ + if (handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_WakeUpEvent, handle->userData); +#else + handle->callback(base, handle, kENET_WakeUpEvent, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + else + { + /* Clear the error interrupt event status. */ + errMask &= base->EIR; + base->EIR = errMask; + /* Callback function. */ + if (handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_ErrEvent, handle->userData); +#else + handle->callback(base, handle, kENET_ErrEvent, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#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_Ptp1588TimerIRQHandler(ENET_Type *base, enet_handle_t *handle) +{ + assert(handle); + + /* Check if the PTP time stamp interrupt happen. */ + if (kENET_TsTimerInterrupt & base->EIR) + { + /* Clear the time stamp interrupt. */ + base->EIR = kENET_TsTimerInterrupt; + + /* Increase timer second counter. */ + handle->msTimerSecond++; + + /* Callback function. */ + if (handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_TimeStampEvent, handle->userData); +#else + handle->callback(base, handle, kENET_TimeStampEvent, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } + else + { + /* Clear the time stamp interrupt. */ + base->EIR = kENET_TsAvailInterrupt; + /* Callback function. */ + if (handle->callback) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + handle->callback(base, handle, 0, kENET_TimeStampAvailEvent, handle->userData); +#else + handle->callback(base, handle, kENET_TimeStampAvailEvent, handle->userData); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#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); + + if (event & (kENET_TxBufferInterrupt | kENET_TxFrameInterrupt)) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + s_enetTxIsr(base, s_ENETHandle[instance], 0); +#else + s_enetTxIsr(base, s_ENETHandle[instance]); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + + if (event & (kENET_RxBufferInterrupt | kENET_RxFrameInterrupt)) + { +#if FSL_FEATURE_ENET_QUEUE > 1 + s_enetRxIsr(base, s_ENETHandle[instance], 0); +#else + s_enetRxIsr(base, s_ENETHandle[instance]); +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + } + + if (event & ENET_TS_INTERRUPT) + { + s_enetTsIsr(base, s_ENETHandle[instance]); + } + if (event & ENET_ERR_INTERRUPT) + { + s_enetErrIsr(base, s_ENETHandle[instance]); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +#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); + + if (event & (kENET_TxBuffer1Interrupt | kENET_TxFrame1Interrupt)) + { + s_enetTxIsr(base, s_ENETHandle[instance], 1); + } + + if (event & (kENET_RxBuffer1Interrupt | kENET_RxFrame1Interrupt)) + { + s_enetRxIsr(base, s_ENETHandle[instance], 1); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +/*! + * 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); + + if (event & (kENET_TxBuffer2Interrupt | kENET_TxFrame2Interrupt)) + { + s_enetTxIsr(base, s_ENETHandle[instance], 2); + } + + if (event & (kENET_RxBuffer2Interrupt | kENET_RxFrame2Interrupt)) + { + s_enetRxIsr(base, s_ENETHandle[instance], 2); + } +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif /* FSL_FEATURE_ENET_QUEUE > 1 */ + +#if defined(ENET) +void ENET_Transmit_IRQHandler(void) +{ + s_enetTxIsr(ENET, s_ENETHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +void ENET_Receive_IRQHandler(void) +{ + s_enetRxIsr(ENET, s_ENETHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +void ENET_Error_IRQHandler(void) +{ + s_enetErrIsr(ENET, s_ENETHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +void ENET_1588_Timer_IRQHandler(void) +{ + s_enetTsIsr(ENET, s_ENETHandle[0]); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +//void ENET_DriverIRQHandler(void) +void ENET_DriverIRQHandler(int vector, void *param) +{ + ENET_CommonFrame0IRQHandler(ENET); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} + +DECLARE_HW_IRQ(ENET_IRQn, ENET_DriverIRQHandler, NONE); + +#endif + +#if defined(ENET1) +void ENET1_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET1); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#if defined(ENET2) +void ENET2_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(ENET2); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif + +#if defined(CONNECTIVITY__ENET0) +void CONNECTIVITY_ENET0_FRAME0_EVENT_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET0); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#if FSL_FEATURE_ENET_QUEUE > 1 +void CONNECTIVITY_ENET0_FRAME1_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET0); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +void CONNECTIVITY_ENET0_FRAME2_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET0); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif +#endif +#if defined(CONNECTIVITY__ENET1) +void CONNECTIVITY_ENET1_FRAME0_EVENT_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame0IRQHandler(CONNECTIVITY__ENET1); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#if FSL_FEATURE_ENET_QUEUE > 1 +void CONNECTIVITY_ENET1_FRAME1_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame1IRQHandler(CONNECTIVITY__ENET1); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +void CONNECTIVITY_ENET1_FRAME2_INT_DriverIRQHandler(void) +{ + ENET_CommonFrame2IRQHandler(CONNECTIVITY__ENET1); +/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F Store immediate overlapping + exception return operation might vector to incorrect interrupt */ +#if defined __CORTEX_M && (__CORTEX_M == 4U) + __DSB(); +#endif +} +#endif +#endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/Makefile new file mode 100755 index 000000000..b6d80e5ea --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/Makefile @@ -0,0 +1,2 @@ +SRC_FILES := fsl_phy.c +include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c new file mode 100755 index 000000000..7f99f8216 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file fsl_phy.c + * @brief phy drivers for ksz8081 + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + +#include "lwipopts.h" +#include "fsl_phy.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief Defines the timeout macro. */ +#define PHY_TIMEOUT_COUNT 100000 + +/******************************************************************************* + * Prototypes + ******************************************************************************/ + +/*! + * @brief Get the ENET instance from peripheral base address. + * + * @param base ENET peripheral base address. + * @return ENET instance. + */ +extern uint32_t ENET_GetInstance(ENET_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to enet clocks for each instance. */ +extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/******************************************************************************* + * Code + ******************************************************************************/ + +status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) +{ + uint32_t bssReg; + uint32_t counter = PHY_TIMEOUT_COUNT; + uint32_t idReg = 0; + status_t result = kStatus_Success; + uint32_t instance = ENET_GetInstance(base); + uint32_t timeDelay; + uint32_t ctlReg = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Set SMI first. */ + CLOCK_EnableClock(s_enetClock[instance]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + ENET_SetSMI(base, srcClock_Hz, false); + + /* Initialization after PHY stars to work. */ + while ((idReg != PHY_CONTROL_ID1) && (counter != 0)) + { + PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg); + counter--; + } + + if (!counter) + { + return kStatus_Fail; + } + + /* Reset PHY. */ + counter = PHY_TIMEOUT_COUNT; + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + if (result == kStatus_Success) + { +#if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE) + uint32_t data = 0; + result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data); + if (result != kStatus_Success) + { + return result; + } + result = PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REFCLK_SELECT_MASK)); + if (result != kStatus_Success) + { + return result; + } +#endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */ + + /* Set the negotiation. */ + result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, + (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | + PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U)); + if (result == kStatus_Success) + { + result = + PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + if (result == kStatus_Success) + { + /* Check auto negotiation complete. */ + while (counter--) + { + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); + if (result == kStatus_Success) + { + PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg); + if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) && (ctlReg & PHY_LINK_READY_MASK)) + { + /* Wait a moment for Phy status stable. */ + for (timeDelay = 0; timeDelay < PHY_TIMEOUT_COUNT; timeDelay++) + { + __ASM("nop"); + } + break; + } + } + + if (!counter) + { + return kStatus_PHY_AutoNegotiateFail; + } + } + } + } + } + + return result; +} + +status_t PHY_Write(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t data) +{ + uint32_t counter; + + /* Clear the SMI interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI write command. */ + ENET_StartSMIWrite(base, phyAddr, phyReg, kENET_MiiWriteValidFrame, data); + + /* Wait for SMI complete. */ + for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--) + { + if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) + { + break; + } + } + + /* Check for timeout. */ + if (!counter) + { + return kStatus_PHY_SMIVisitTimeout; + } + + /* Clear MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return kStatus_Success; +} + +status_t PHY_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr) +{ + assert(dataPtr); + + uint32_t counter; + + /* Clear the MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + /* Starts a SMI read command operation. */ + ENET_StartSMIRead(base, phyAddr, phyReg, kENET_MiiReadValidFrame); + + /* Wait for MII complete. */ + for (counter = PHY_TIMEOUT_COUNT; counter > 0; counter--) + { + if (ENET_GetInterruptStatus(base) & ENET_EIR_MII_MASK) + { + break; + } + } + + /* Check for timeout. */ + if (!counter) + { + return kStatus_PHY_SMIVisitTimeout; + } + + /* Get data from MII register. */ + *dataPtr = ENET_ReadSMIData(base); + + /* Clear MII interrupt event. */ + ENET_ClearInterruptStatus(base, ENET_EIR_MII_MASK); + + return kStatus_Success; +} + +status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable) +{ + status_t result; + uint32_t data = 0; + + /* Set the loop mode. */ + if (enable) + { + if (mode == kPHY_LocalLoop) + { + if (speed == kPHY_Speed100M) + { + data = PHY_BCTL_SPEED_100M_MASK | PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + else + { + data = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + } + return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, data); + } + else + { + /* First read the current status in control register. */ + result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data); + if (result == kStatus_Success) + { + return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REMOTELOOP_MASK)); + } + } + } + else + { + /* Disable the loop mode. */ + if (mode == kPHY_LocalLoop) + { + /* First read the current status in control register. */ + result = PHY_Read(base, phyAddr, PHY_BASICCONTROL_REG, &data); + if (result == kStatus_Success) + { + data &= ~PHY_BCTL_LOOP_MASK; + return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (data | PHY_BCTL_RESTART_AUTONEG_MASK)); + } + } + else + { + /* First read the current status in control one register. */ + result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data); + if (result == kStatus_Success) + { + return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data & ~PHY_CTL2_REMOTELOOP_MASK)); + } + } + } + return result; +} + +status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status) +{ + assert(status); + + status_t result = kStatus_Success; + uint32_t data; + + /* Read the basic status register. */ + result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &data); + if (result == kStatus_Success) + { + if (!(PHY_BSTATUS_LINKSTATUS_MASK & data)) + { + /* link down. */ + *status = false; + } + else + { + /* link up. */ + *status = true; + } + } + return result; +} + +status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex) +{ + assert(duplex); + + status_t result = kStatus_Success; + uint32_t data, ctlReg; + + + /* Read the control two register. */ + result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg); + if (result == kStatus_Success) + { + data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK; + if ((PHY_CTL1_10FULLDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data)) + { + /* Full duplex. */ + *duplex = kPHY_FullDuplex; + } + else + { + /* Half duplex. */ + *duplex = kPHY_HalfDuplex; + } + + data = ctlReg & PHY_CTL1_SPEEDUPLX_MASK; + if ((PHY_CTL1_100HALFDUPLEX_MASK == data) || (PHY_CTL1_100FULLDUPLEX_MASK == data)) + { + /* 100M speed. */ + *speed = kPHY_Speed100M; + } + else + { /* 10M speed. */ + *speed = kPHY_Speed10M; + } + } + + return result; +} diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h new file mode 100755 index 000000000..3f0e905fa --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * Copyright 2016-2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file fsl_phy.h + * @brief phy drivers for ksz8081 + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + +#ifndef _FSL_PHY_H_ +#define _FSL_PHY_H_ + +#include "fsl_enet.h" + +/*! + * @addtogroup phy_driver + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @brief PHY driver version */ +#define FSL_PHY_DRIVER_VERSION (MAKE_VERSION(2, 0, 0)) /*!< Version 2.0.0. */ + +/*! @brief Defines the 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_CONTROL1_REG 0x1EU /*!< The PHY control one register. */ +#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */ + +#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1*/ + +/*! @brief Defines the mask flag in basic control register. */ +#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_SPEED_MASK 0x2000U /*!< The PHY speed bit mask. */ +#define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */ +#define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */ +#define PHY_BCTL_SPEED_100M_MASK 0x2000U /*!< The PHY 100M speed mask. */ + +/*!@brief Defines the mask flag of operation mode in control two register*/ +#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 mask flag in basic status register. */ +#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_AUTONEGCOMP_MASK 0x0020U /*!< The PHY auto-negotiation complete mask. */ + +/*! @brief Defines the mask flag in PHY auto-negotiation advertise register. */ +#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.*/ + +/*! @brief Defines the PHY status. */ +enum _phy_status +{ + kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 1), /*!< ENET PHY SMI visit timeout. */ + kStatus_PHY_AutoNegotiateFail = MAKE_STATUS(kStatusGroup_PHY, 2) /*!< ENET PHY AutoNegotiate Fail. */ +}; + +/*! @brief Defines the PHY link speed. This is align with the speed for ENET MAC. */ +typedef enum _phy_speed +{ + kPHY_Speed10M = 0U, /*!< ENET PHY 10M speed. */ + kPHY_Speed100M /*!< ENET PHY 100M 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 loopback. */ + kPHY_RemoteLoop /*!< ENET PHY remote loopback. */ +} phy_loop_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name PHY Driver + * @{ + */ + +/*! + * @brief Initializes PHY. + * + * This function initialize the SMI interface and initialize PHY. + * The SMI is the MII management interface between PHY and MAC, which should be + * firstly initialized before any other operation for PHY. The PHY initialize with auto-negotiation. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param srcClock_Hz The module clock frequency - system clock for MII management interface - SMI. + * @retval kStatus_Success PHY initialize success + * @retval kStatus_PHY_SMIVisitTimeout PHY SMI visit time out + * @retval kStatus_PHY_AutoNegotiateFail PHY auto negotiate fail + */ +status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz); + +/*! + * @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 base ENET peripheral base address. + * @param phyAddr The PHY address. + * @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_Write(ENET_Type *base, uint32_t phyAddr, 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 base ENET peripheral base address. + * @param phyAddr The PHY address. + * @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_Read(ENET_Type *base, uint32_t phyAddr, uint32_t phyReg, uint32_t *dataPtr); + +/*! + * @brief Enables/disables PHY loopback. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @param mode The loopback mode to be enabled, please see "phy_loop_t". + * the two loopback mode should not be both set. when one loopback mode is set + * the other one 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_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, phy_speed_t speed, bool enable); + +/*! + * @brief Gets the PHY link status. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @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 + */ +status_t PHY_GetLinkStatus(ENET_Type *base, uint32_t phyAddr, bool *status); + +/*! + * @brief Gets the PHY link speed and duplex. + * + * @param base ENET peripheral base address. + * @param phyAddr The PHY address. + * @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 + */ +status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t *speed, phy_duplex_t *duplex); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_PHY_H_ */ diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ethernet.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ethernet.h new file mode 100755 index 000000000..376c004fe --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/connect_ethernet.h @@ -0,0 +1,39 @@ +/* +* 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_ + +#ifdef __cplusplus + extern "C" { +#endif + + +#ifndef sourceClock +#define sourceClock CLOCK_GetFreq(kCLOCK_CoreSysClk) +#endif + + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif.h new file mode 100755 index 000000000..8416d75bc --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif.h @@ -0,0 +1,192 @@ +/* + * 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-2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file enet_ethernetif.h + * @brief ethernet drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + + +#ifndef ENET_ETHERNETIF_H +#define ENET_ETHERNETIF_H + +#include "lwip/err.h" +#include "lwip/netif.h" +#include "fsl_enet.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ +#ifndef ENET_RXBD_NUM + #define ENET_RXBD_NUM (5) +#endif +#ifndef ENET_TXBD_NUM +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + #define ENET_TXBD_NUM (5) +#else + #define ENET_TXBD_NUM (3) +#endif +#endif +#ifndef ENET_RXBUFF_SIZE +#if defined(FSL_FEATURE_SOC_LPC_ENET_COUNT) && (FSL_FEATURE_SOC_LPC_ENET_COUNT > 0) + #define ENET_RXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN + ETH_PAD_SIZE) +#else + #define ENET_RXBUFF_SIZE ENET_FRAME_MAX_FRAMELEN +#endif +#endif + +#ifndef ENET_TXBUFF_SIZE + #define ENET_TXBUFF_SIZE (ENET_FRAME_MAX_FRAMELEN) +#endif + +#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 (15U)//(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 (0xFFFU) +#endif + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +#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 + +#define ENET_RING_NUM 1U + +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)]; + +#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 +{ + uint32_t phyAddress; + clock_name_t clockName; + 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); + +void ETH_BSP_Config(void); + +int32 lwip_obtain_semaphore(struct netif *netif); + +#if defined(__cplusplus) +} +#endif /* __cplusplus */ + +#endif /* ENET_ETHERNETIF_H */ diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif_priv.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif_priv.h new file mode 100755 index 000000000..559466736 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/enet_ethernetif_priv.h @@ -0,0 +1,82 @@ +/* + * Copyright 2019 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/** + * @file enet_ethernetif_priv.h + * @brief ethernet drivers + * @version 1.0 + * @author AIIT XUOS Lab + * @date 2021.11.11 + */ + + +#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, + const uint8_t enetIdx, + 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, + enet_config_t *config); + +ENET_Type **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/xidatong/third_party_driver/include/fsl_semc.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/fsl_semc.h new file mode 100644 index 000000000..75704eadf --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/include/fsl_semc.h @@ -0,0 +1,830 @@ +/* + * Copyright 2017-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef _FSL_SEMC_H_ +#define _FSL_SEMC_H_ + +#include "fsl_common.h" + +/*! + * @addtogroup semc + * @{ + */ + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/*! @name Driver version */ +/*@{*/ +/*! @brief SEMC driver version 2.0.4. */ +#define FSL_SEMC_DRIVER_VERSION (MAKE_VERSION(2, 0, 4)) +/*@}*/ + +/*! @brief SEMC status. */ +enum _semc_status +{ + kStatus_SEMC_InvalidDeviceType = MAKE_STATUS(kStatusGroup_SEMC, 0), + kStatus_SEMC_IpCommandExecutionError = MAKE_STATUS(kStatusGroup_SEMC, 1), + kStatus_SEMC_AxiCommandExecutionError = MAKE_STATUS(kStatusGroup_SEMC, 2), + kStatus_SEMC_InvalidMemorySize = MAKE_STATUS(kStatusGroup_SEMC, 3), + kStatus_SEMC_InvalidIpcmdDataSize = MAKE_STATUS(kStatusGroup_SEMC, 4), + kStatus_SEMC_InvalidAddressPortWidth = MAKE_STATUS(kStatusGroup_SEMC, 5), + kStatus_SEMC_InvalidDataPortWidth = MAKE_STATUS(kStatusGroup_SEMC, 6), + kStatus_SEMC_InvalidSwPinmuxSelection = MAKE_STATUS(kStatusGroup_SEMC, 7), + kStatus_SEMC_InvalidBurstLength = MAKE_STATUS(kStatusGroup_SEMC, 8), + kStatus_SEMC_InvalidColumnAddressBitWidth = MAKE_STATUS(kStatusGroup_SEMC, 9), + kStatus_SEMC_InvalidBaseAddress = MAKE_STATUS(kStatusGroup_SEMC, 10), + kStatus_SEMC_InvalidTimerSetting = MAKE_STATUS(kStatusGroup_SEMC, 11), +}; + +/*! @brief SEMC memory device type. */ +typedef enum _semc_mem_type +{ + kSEMC_MemType_SDRAM = 0, /*!< SDRAM */ + kSEMC_MemType_SRAM, /*!< SRAM */ + kSEMC_MemType_NOR, /*!< NOR */ + kSEMC_MemType_NAND, /*!< NAND */ + kSEMC_MemType_8080 /*!< 8080. */ +} semc_mem_type_t; + +/*! @brief SEMC WAIT/RDY polarity. */ +typedef enum _semc_waitready_polarity +{ + kSEMC_LowActive = 0, /*!< Low active. */ + kSEMC_HighActive, /*!< High active. */ +} semc_waitready_polarity_t; + +/*! @brief SEMC SDRAM Chip selection . */ +typedef enum _semc_sdram_cs +{ + kSEMC_SDRAM_CS0 = 0, /*!< SEMC SDRAM CS0. */ + kSEMC_SDRAM_CS1, /*!< SEMC SDRAM CS1. */ + kSEMC_SDRAM_CS2, /*!< SEMC SDRAM CS2. */ + kSEMC_SDRAM_CS3 /*!< SEMC SDRAM CS3. */ +} semc_sdram_cs_t; + +/*! @brief SEMC NAND device type. */ +typedef enum _semc_nand_access_type +{ + kSEMC_NAND_ACCESS_BY_AXI = 0, + kSEMC_NAND_ACCESS_BY_IPCMD, +} semc_nand_access_type_t; + +/*! @brief SEMC interrupts . */ +typedef enum _semc_interrupt_enable +{ + kSEMC_IPCmdDoneInterrupt = SEMC_INTEN_IPCMDDONEEN_MASK, /*!< Ip command done interrupt. */ + kSEMC_IPCmdErrInterrupt = SEMC_INTEN_IPCMDERREN_MASK, /*!< Ip command error interrupt. */ + kSEMC_AXICmdErrInterrupt = SEMC_INTEN_AXICMDERREN_MASK, /*!< AXI command error interrupt. */ + kSEMC_AXIBusErrInterrupt = SEMC_INTEN_AXIBUSERREN_MASK /*!< AXI bus error interrupt. */ +} semc_interrupt_enable_t; + +/*! @brief SEMC IP command data size in bytes. */ +typedef enum _semc_ipcmd_datasize +{ + kSEMC_IPcmdDataSize_1bytes = 1, /*!< The IP command data size 1 byte. */ + kSEMC_IPcmdDataSize_2bytes, /*!< The IP command data size 2 byte. */ + kSEMC_IPcmdDataSize_3bytes, /*!< The IP command data size 3 byte. */ + kSEMC_IPcmdDataSize_4bytes /*!< The IP command data size 4 byte. */ +} semc_ipcmd_datasize_t; + +/*! @brief SEMC auto-refresh timing. */ +typedef enum _semc_refresh_time +{ + kSEMC_RefreshThreeClocks = 0x0U, /*!< The refresh timing with three bus clocks. */ + kSEMC_RefreshSixClocks, /*!< The refresh timing with six bus clocks. */ + kSEMC_RefreshNineClocks /*!< The refresh timing with nine bus clocks. */ +} semc_refresh_time_t; + +/*! @brief CAS latency */ +typedef enum _semc_caslatency +{ + kSEMC_LatencyOne = 1, /*!< Latency 1. */ + kSEMC_LatencyTwo, /*!< Latency 2. */ + kSEMC_LatencyThree, /*!< Latency 3. */ +} semc_caslatency_t; + +/*! @brief SEMC sdram column address bit number. */ +typedef enum _semc_sdram_column_bit_num +{ + kSEMC_SdramColunm_12bit = 0x0U, /*!< 12 bit. */ + kSEMC_SdramColunm_11bit, /*!< 11 bit. */ + kSEMC_SdramColunm_10bit, /*!< 10 bit. */ + kSEMC_SdramColunm_9bit, /*!< 9 bit. */ +} semc_sdram_column_bit_num_t; + +/*! @brief SEMC sdram burst length. */ +typedef enum _semc_sdram_burst_len +{ + kSEMC_Sdram_BurstLen1 = 0, /*!< Burst length 1*/ + kSEMC_Sdram_BurstLen2, /*!< Burst length 2*/ + kSEMC_Sdram_BurstLen4, /*!< Burst length 4*/ + kSEMC_Sdram_BurstLen8 /*!< Burst length 8*/ +} sem_sdram_burst_len_t; + +/*! @brief SEMC nand column address bit number. */ +typedef enum _semc_nand_column_bit_num +{ + kSEMC_NandColum_16bit = 0x0U, /*!< 16 bit. */ + kSEMC_NandColum_15bit, /*!< 15 bit. */ + kSEMC_NandColum_14bit, /*!< 14 bit. */ + kSEMC_NandColum_13bit, /*!< 13 bit. */ + kSEMC_NandColum_12bit, /*!< 12 bit. */ + kSEMC_NandColum_11bit, /*!< 11 bit. */ + kSEMC_NandColum_10bit, /*!< 10 bit. */ + kSEMC_NandColum_9bit, /*!< 9 bit. */ +} semc_nand_column_bit_num_t; + +/*! @brief SEMC nand burst length. */ +typedef enum _semc_nand_burst_len +{ + kSEMC_Nand_BurstLen1 = 0, /*!< Burst length 1*/ + kSEMC_Nand_BurstLen2, /*!< Burst length 2*/ + kSEMC_Nand_BurstLen4, /*!< Burst length 4*/ + kSEMC_Nand_BurstLen8, /*!< Burst length 8*/ + kSEMC_Nand_BurstLen16, /*!< Burst length 16*/ + kSEMC_Nand_BurstLen32, /*!< Burst length 32*/ + kSEMC_Nand_BurstLen64 /*!< Burst length 64*/ +} sem_nand_burst_len_t; + +/*! @brief SEMC nor/sram column address bit number. */ +typedef enum _semc_norsram_column_bit_num +{ + kSEMC_NorColum_12bit = 0x0U, /*!< 12 bit. */ + kSEMC_NorColum_11bit, /*!< 11 bit. */ + kSEMC_NorColum_10bit, /*!< 10 bit. */ + kSEMC_NorColum_9bit, /*!< 9 bit. */ + kSEMC_NorColum_8bit, /*!< 8 bit. */ + kSEMC_NorColum_7bit, /*!< 7 bit. */ + kSEMC_NorColum_6bit, /*!< 6 bit. */ + kSEMC_NorColum_5bit, /*!< 5 bit. */ + kSEMC_NorColum_4bit, /*!< 4 bit. */ + kSEMC_NorColum_3bit, /*!< 3 bit. */ + kSEMC_NorColum_2bit /*!< 2 bit. */ +} semc_norsram_column_bit_num_t; + +/*! @brief SEMC nor/sram burst length. */ +typedef enum _semc_norsram_burst_len +{ + kSEMC_Nor_BurstLen1 = 0, /*!< Burst length 1*/ + kSEMC_Nor_BurstLen2, /*!< Burst length 2*/ + kSEMC_Nor_BurstLen4, /*!< Burst length 4*/ + kSEMC_Nor_BurstLen8, /*!< Burst length 8*/ + kSEMC_Nor_BurstLen16, /*!< Burst length 16*/ + kSEMC_Nor_BurstLen32, /*!< Burst length 32*/ + kSEMC_Nor_BurstLen64 /*!< Burst length 64*/ +} sem_norsram_burst_len_t; + +/*! @brief SEMC dbi column address bit number. */ +typedef enum _semc_dbi_column_bit_num +{ + kSEMC_Dbi_Colum_12bit = 0x0U, /*!< 12 bit. */ + kSEMC_Dbi_Colum_11bit, /*!< 11 bit. */ + kSEMC_Dbi_Colum_10bit, /*!< 10 bit. */ + kSEMC_Dbi_Colum_9bit, /*!< 9 bit. */ + kSEMC_Dbi_Colum_8bit, /*!< 8 bit. */ + kSEMC_Dbi_Colum_7bit, /*!< 7 bit. */ + kSEMC_Dbi_Colum_6bit, /*!< 6 bit. */ + kSEMC_Dbi_Colum_5bit, /*!< 5 bit. */ + kSEMC_Dbi_Colum_4bit, /*!< 4 bit. */ + kSEMC_Dbi_Colum_3bit, /*!< 3 bit. */ + kSEMC_Dbi_Colum_2bit /*!< 2 bit. */ +} semc_dbi_column_bit_num_t; + +/*! @brief SEMC dbi burst length. */ +typedef enum _semc_dbi_burst_len +{ + kSEMC_Dbi_BurstLen1 = 0, /*!< Burst length 1*/ + kSEMC_Dbi_BurstLen2, /*!< Burst length 2*/ + kSEMC_Dbi_Dbi_BurstLen4, /*!< Burst length 4*/ + kSEMC_Dbi_BurstLen8, /*!< Burst length 8*/ + kSEMC_Dbi_BurstLen16, /*!< Burst length 16*/ + kSEMC_Dbi_BurstLen32, /*!< Burst length 32*/ + kSEMC_Dbi_BurstLen64 /*!< Burst length 64*/ +} sem_dbi_burst_len_t; + +/*! @brief SEMC IOMUXC. */ +typedef enum _semc_iomux_pin +{ + kSEMC_MUXA8 = SEMC_IOCR_MUX_A8_SHIFT, /*!< MUX A8 pin. */ + kSEMC_MUXCSX0 = SEMC_IOCR_MUX_CSX0_SHIFT, /*!< MUX CSX0 pin */ + kSEMC_MUXCSX1 = SEMC_IOCR_MUX_CSX1_SHIFT, /*!< MUX CSX1 Pin.*/ + kSEMC_MUXCSX2 = SEMC_IOCR_MUX_CSX2_SHIFT, /*!< MUX CSX2 Pin. */ + kSEMC_MUXCSX3 = SEMC_IOCR_MUX_CSX3_SHIFT, /*!< MUX CSX3 Pin. */ + kSEMC_MUXRDY = SEMC_IOCR_MUX_RDY_SHIFT /*!< MUX RDY pin. */ +} semc_iomux_pin; + +/*! @brief SEMC NOR/PSRAM Address bit 27 A27. */ +typedef enum _semc_iomux_nora27_pin +{ + kSEMC_MORA27_NONE = 0, /*!< No NOR/SRAM A27 pin. */ + kSEMC_NORA27_MUXCSX3 = SEMC_IOCR_MUX_CSX3_SHIFT, /*!< MUX CSX3 Pin. */ + kSEMC_NORA27_MUXRDY = SEMC_IOCR_MUX_RDY_SHIFT /*!< MUX RDY pin. */ +} semc_iomux_nora27_pin; + +/*! @brief SEMC port size. */ +typedef enum _semc_port_size +{ + kSEMC_PortSize8Bit = 0, /*!< 8-Bit port size. */ + kSEMC_PortSize16Bit /*!< 16-Bit port size. */ +} smec_port_size_t; + +/*! @brief SEMC address mode. */ +typedef enum _semc_addr_mode +{ + kSEMC_AddrDataMux = 0, /*!< SEMC address/data mux mode. */ + kSEMC_AdvAddrdataMux, /*!< Advanced address/data mux mode. */ + kSEMC_AddrDataNonMux /*!< Address/data non-mux mode. */ +} semc_addr_mode_t; + +/*! @brief SEMC DQS read strobe mode. */ +typedef enum _semc_dqs_mode +{ + kSEMC_Loopbackinternal = 0, /*!< Dummy read strobe loopbacked internally. */ + kSEMC_Loopbackdqspad, /*!< Dummy read strobe loopbacked from DQS pad. */ +} semc_dqs_mode_t; + +/*! @brief SEMC ADV signal active polarity. */ +typedef enum _semc_adv_polarity +{ + kSEMC_AdvActiveLow = 0, /*!< Adv active low. */ + kSEMC_AdvActivehigh, /*!< Adv active low. */ +} semc_adv_polarity_t; + +/*! @brief SEMC RDY signal active polarity. */ +typedef enum _semc_rdy_polarity +{ + kSEMC_RdyActiveLow = 0, /*!< Adv active low. */ + kSEMC_RdyActivehigh, /*!< Adv active low. */ +} semc_rdy_polarity_t; + +/*! @brief SEMC IP command for NAND: address mode. */ +typedef enum _semc_ipcmd_nand_addrmode +{ + kSEMC_NANDAM_ColumnRow = 0x0U, /*!< Address mode: column and row address(5Byte-CA0/CA1/RA0/RA1/RA2). */ + kSEMC_NANDAM_ColumnCA0, /*!< Address mode: column address only(1 Byte-CA0). */ + kSEMC_NANDAM_ColumnCA0CA1, /*!< Address mode: column address only(2 Byte-CA0/CA1). */ + kSEMC_NANDAM_RawRA0, /*!< Address mode: row address only(1 Byte-RA0). */ + kSEMC_NANDAM_RawRA0RA1, /*!< Address mode: row address only(2 Byte-RA0/RA1). */ + kSEMC_NANDAM_RawRA0RA1RA2 /*!< Address mode: row address only(3 Byte-RA0). */ +} semc_ipcmd_nand_addrmode_t; + +/*! @brief SEMC IP command for NAND: command mode. */ +typedef enum _semc_ipcmd_nand_cmdmode +{ + kSEMC_NANDCM_Command = 0x2U, /*!< command. */ + kSEMC_NANDCM_CommandHold, /*!< Command hold. */ + kSEMC_NANDCM_CommandAddress, /*!< Command address. */ + kSEMC_NANDCM_CommandAddressHold, /*!< Command address hold. */ + kSEMC_NANDCM_CommandAddressRead, /*!< Command address read. */ + kSEMC_NANDCM_CommandAddressWrite, /*!< Command address write. */ + kSEMC_NANDCM_CommandRead, /*!< Command read. */ + kSEMC_NANDCM_CommandWrite, /*!< Command write. */ + kSEMC_NANDCM_Read, /*!< Read. */ + kSEMC_NANDCM_Write /*!< Write. */ +} semc_ipcmd_nand_cmdmode_t; + +/*! @brief SEMC NAND address option. */ +typedef enum _semc_nand_address_option +{ + kSEMC_NandAddrOption_5byte_CA2RA3 = 0U, /*!< CA0+CA1+RA0+RA1+RA2 */ + kSEMC_NandAddrOption_4byte_CA2RA2 = 2U, /*!< CA0+CA1+RA0+RA1 */ + kSEMC_NandAddrOption_3byte_CA2RA1 = 4U, /*!< CA0+CA1+RA0 */ + kSEMC_NandAddrOption_4byte_CA1RA3 = 1U, /*!< CA0+RA0+RA1+RA2 */ + kSEMC_NandAddrOption_3byte_CA1RA2 = 3U, /*!< CA0+RA0+RA1 */ + kSEMC_NandAddrOption_2byte_CA1RA1 = 7U, /*!< CA0+RA0 */ +} semc_nand_address_option_t; + +/*! @brief SEMC IP command for NOR. */ +typedef enum _semc_ipcmd_nor_dbi +{ + kSEMC_NORDBICM_Read = 0x2U, /*!< NOR read. */ + kSEMC_NORDBICM_Write /*!< NOR write. */ +} semc_ipcmd_nor_dbi_t; + +/*! @brief SEMC IP command for SRAM. */ +typedef enum _semc_ipcmd_sram +{ + kSEMC_SRAMCM_ArrayRead = 0x2U, /*!< SRAM memory array read. */ + kSEMC_SRAMCM_ArrayWrite, /*!< SRAM memory array write. */ + kSEMC_SRAMCM_RegRead, /*!< SRAM memory register read. */ + kSEMC_SRAMCM_RegWrite /*!< SRAM memory register write. */ +} semc_ipcmd_sram_t; + +/*! @brief SEMC IP command for SDARM. */ +typedef enum _semc_ipcmd_sdram +{ + kSEMC_SDRAMCM_Read = 0x8U, /*!< SDRAM memory read. */ + kSEMC_SDRAMCM_Write, /*!< SDRAM memory write. */ + kSEMC_SDRAMCM_Modeset, /*!< SDRAM MODE SET. */ + kSEMC_SDRAMCM_Active, /*!< SDRAM active. */ + kSEMC_SDRAMCM_AutoRefresh, /*!< SDRAM auto-refresh. */ + kSEMC_SDRAMCM_SelfRefresh, /*!< SDRAM self-refresh. */ + kSEMC_SDRAMCM_Precharge, /*!< SDRAM precharge. */ + kSEMC_SDRAMCM_Prechargeall /*!< SDRAM precharge all. */ +} semc_ipcmd_sdram_t; + +/*! @brief SEMC SDRAM configuration structure. + * + * 1. The memory size in the configuration is in the unit of KB. So memsize_kbytes + * should be set as 2^2, 2^3, 2^4 .etc which is base 2KB exponential function. + * Take refer to BR0~BR3 register in RM for details. + * 2. The prescalePeriod_N16Cycle is in unit of 16 clock cycle. It is a exception for prescaleTimer_n16cycle = 0, + * it means the prescaler timer period is 256 * 16 clock cycles. For precalerIf precalerTimer_n16cycle not equal to 0, + * The prescaler timer period is prescalePeriod_N16Cycle * 16 clock cycles. + * idleTimeout_NprescalePeriod, refreshUrgThreshold_NprescalePeriod, refreshPeriod_NprescalePeriod are + * similar to prescalePeriod_N16Cycle. + * + */ +typedef struct _semc_sdram_config +{ + semc_iomux_pin csxPinMux; /*!< CS pin mux. The kSEMC_MUXA8 is not valid in sdram pin mux setting. */ + uint32_t address; /*!< The base address. */ + uint32_t memsize_kbytes; /*!< The memory size in unit of kbytes. */ + smec_port_size_t portSize; /*!< Port size. */ + sem_sdram_burst_len_t burstLen; /*!< Burst length. */ + semc_sdram_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */ + semc_caslatency_t casLatency; /*!< CAS latency. */ + uint8_t tPrecharge2Act_Ns; /*!< Precharge to active wait time in unit of nanosecond. */ + uint8_t tAct2ReadWrite_Ns; /*!< Act to read/write wait time in unit of nanosecond. */ + uint8_t tRefreshRecovery_Ns; /*!< Refresh recovery time in unit of nanosecond. */ + uint8_t tWriteRecovery_Ns; /*!< write recovery time in unit of nanosecond. */ + uint8_t tCkeOff_Ns; /*!< CKE off minimum time in unit of nanosecond. */ + uint8_t tAct2Prechage_Ns; /*!< Active to precharge in unit of nanosecond. */ + uint8_t tSelfRefRecovery_Ns; /*!< Self refresh recovery time in unit of nanosecond. */ + uint8_t tRefresh2Refresh_Ns; /*!< Refresh to refresh wait time in unit of nanosecond. */ + uint8_t tAct2Act_Ns; /*!< Active to active wait time in unit of nanosecond. */ + uint32_t tPrescalePeriod_Ns; /*!< Prescaler timer period should not be larger than 256 * 16 * clock cycle. */ + uint32_t tIdleTimeout_Ns; /*!< Idle timeout in unit of prescale time period. */ + uint32_t refreshPeriod_nsPerRow; /*!< Refresh timer period like 64ms * 1000000/8192 . */ + uint32_t refreshUrgThreshold; /*!< Refresh urgent threshold. */ + uint8_t refreshBurstLen; /*!< Refresh burst length. */ +} semc_sdram_config_t; + +/*! @brief SEMC NAND device timing configuration structure. */ +typedef struct _semc_nand_timing_config +{ + uint8_t tCeSetup_Ns; /*!< CE setup time: tCS. */ + uint8_t tCeHold_Ns; /*!< CE hold time: tCH. */ + uint8_t tCeInterval_Ns; /*!< CE interval time:tCEITV. */ + uint8_t tWeLow_Ns; /*!< WE low time: tWP. */ + uint8_t tWeHigh_Ns; /*!< WE high time: tWH. */ + uint8_t tReLow_Ns; /*!< RE low time: tRP. */ + uint8_t tReHigh_Ns; /*!< RE high time: tREH. */ + uint8_t tTurnAround_Ns; /*!< Turnaround time for async mode: tTA. */ + uint8_t tWehigh2Relow_Ns; /*!< WE# high to RE# wait time: tWHR. */ + uint8_t tRehigh2Welow_Ns; /*!< RE# high to WE# low wait time: tRHW. */ + uint8_t tAle2WriteStart_Ns; /*!< ALE to write start wait time: tADL. */ + uint8_t tReady2Relow_Ns; /*!< Ready to RE# low min wait time: tRR. */ + uint8_t tWehigh2Busy_Ns; /*!< WE# high to busy wait time: tWB. */ +} semc_nand_timing_config_t; + +/*! @brief SEMC NAND configuration structure. */ +typedef struct _semc_nand_config +{ + semc_iomux_pin cePinMux; /*!< The CE pin mux setting. The kSEMC_MUXRDY is not valid for CE pin setting. */ + uint32_t axiAddress; /*!< The base address for AXI nand. */ + uint32_t axiMemsize_kbytes; /*!< The memory size in unit of kbytes for AXI nand. */ + uint32_t ipgAddress; /*!< The base address for IPG nand . */ + uint32_t ipgMemsize_kbytes; /*!< The memory size in unit of kbytes for IPG nand. */ + semc_rdy_polarity_t rdyactivePolarity; /*!< Wait ready polarity. */ + bool edoModeEnabled; /*!< EDO mode enabled. */ + semc_nand_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */ + semc_nand_address_option_t arrayAddrOption; /*!< Address option. */ + sem_nand_burst_len_t burstLen; /*!< Burst length. */ + smec_port_size_t portSize; /*!< Port size. */ + semc_nand_timing_config_t *timingConfig; /*!< SEMC nand timing configuration. */ +} semc_nand_config_t; + +/*! @brief SEMC NOR configuration structure. */ +typedef struct _semc_nor_config +{ + semc_iomux_pin cePinMux; /*!< The CE# pin mux setting. */ + semc_iomux_nora27_pin addr27; /*!< The Addr bit 27 pin mux setting. */ + uint32_t address; /*!< The base address. */ + uint32_t memsize_kbytes; /*!< The memory size in unit of kbytes. */ + uint8_t addrPortWidth; /*!< The address port width. */ + semc_rdy_polarity_t rdyactivePolarity; /*!< Wait ready polarity. */ + semc_adv_polarity_t advActivePolarity; /*!< ADV# polarity. */ + semc_norsram_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */ + semc_addr_mode_t addrMode; /*!< Address mode. */ + sem_norsram_burst_len_t burstLen; /*!< Burst length. */ + smec_port_size_t portSize; /*!< Port size. */ + uint8_t tCeSetup_Ns; /*!< The CE setup time. */ + uint8_t tCeHold_Ns; /*!< The CE hold time. */ + uint8_t tCeInterval_Ns; /*!< CE interval minimum time. */ + uint8_t tAddrSetup_Ns; /*!< The address setup time. */ + uint8_t tAddrHold_Ns; /*!< The address hold time. */ + uint8_t tWeLow_Ns; /*!< WE low time for async mode. */ + uint8_t tWeHigh_Ns; /*!< WE high time for async mode. */ + uint8_t tReLow_Ns; /*!< RE low time for async mode. */ + uint8_t tReHigh_Ns; /*!< RE high time for async mode. */ + uint8_t tTurnAround_Ns; /*!< Turnaround time for async mode. */ + uint8_t tAddr2WriteHold_Ns; /*!< Address to write data hold time for async mode. */ +#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) + uint8_t tWriteSetup_Ns; /*!< Write data setup time for sync mode.*/ +#endif +#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) + uint8_t tWriteHold_Ns; /*!< Write hold time for sync mode. */ +#endif + uint8_t latencyCount; /*!< Latency count for sync mode. */ + uint8_t readCycle; /*!< Read cycle time for sync mode. */ +} semc_nor_config_t; + +/*! @brief SEMC SRAM configuration structure. */ +typedef struct _semc_sram_config +{ + semc_iomux_pin cePinMux; /*!< The CE# pin mux setting. */ + semc_iomux_nora27_pin addr27; /*!< The Addr bit 27 pin mux setting. */ + uint32_t address; /*!< The base address. */ + uint32_t memsize_kbytes; /*!< The memory size in unit of kbytes. */ + uint8_t addrPortWidth; /*!< The address port width. */ + semc_adv_polarity_t advActivePolarity; /*!< ADV# polarity 1: active high, 0: active low. */ + semc_addr_mode_t addrMode; /*!< Address mode. */ + sem_norsram_burst_len_t burstLen; /*!< Burst length. */ + smec_port_size_t portSize; /*!< Port size. */ + uint8_t tCeSetup_Ns; /*!< The CE setup time. */ + uint8_t tCeHold_Ns; /*!< The CE hold time. */ + uint8_t tCeInterval_Ns; /*!< CE interval minimum time. */ + uint8_t tAddrSetup_Ns; /*!< The address setup time. */ + uint8_t tAddrHold_Ns; /*!< The address hold time. */ + uint8_t tWeLow_Ns; /*!< WE low time for async mode. */ + uint8_t tWeHigh_Ns; /*!< WE high time for async mode. */ + uint8_t tReLow_Ns; /*!< RE low time for async mode. */ + uint8_t tReHigh_Ns; /*!< RE high time for async mode. */ + uint8_t tTurnAround_Ns; /*!< Turnaround time for async mode. */ + uint8_t tAddr2WriteHold_Ns; /*!< Address to write data hold time for async mode. */ + uint8_t tWriteSetup_Ns; /*!< Write data setup time for sync mode.*/ + uint8_t tWriteHold_Ns; /*!< Write hold time for sync mode. */ + uint8_t latencyCount; /*!< Latency count for sync mode. */ + uint8_t readCycle; /*!< Read cycle time for sync mode. */ +} semc_sram_config_t; + +/*! @brief SEMC DBI configuration structure. */ +typedef struct _semc_dbi_config +{ + semc_iomux_pin csxPinMux; /*!< The CE# pin mux. */ + uint32_t address; /*!< The base address. */ + uint32_t memsize_kbytes; /*!< The memory size in unit of 4kbytes. */ + semc_dbi_column_bit_num_t columnAddrBitNum; /*!< Column address bit number. */ + sem_dbi_burst_len_t burstLen; /*!< Burst length. */ + smec_port_size_t portSize; /*!< Port size. */ + uint8_t tCsxSetup_Ns; /*!< The CSX setup time. */ + uint8_t tCsxHold_Ns; /*!< The CSX hold time. */ + uint8_t tWexLow_Ns; /*!< WEX low time. */ + uint8_t tWexHigh_Ns; /*!< WEX high time. */ + uint8_t tRdxLow_Ns; /*!< RDX low time. */ + uint8_t tRdxHigh_Ns; /*!< RDX high time. */ + uint8_t tCsxInterval_Ns; /*!< Write data setup time.*/ +} semc_dbi_config_t; + +/*! @brief SEMC AXI queue a weight setting structure. */ +typedef struct _semc_queuea_weight_struct +{ + uint32_t qos : 4; /*!< weight of qos for queue 0 . */ + uint32_t aging : 4; /*!< weight of aging for queue 0.*/ + uint32_t slaveHitSwith : 8; /*!< weight of read/write switch for queue 0.*/ + uint32_t slaveHitNoswitch : 8; /*!< weight of read/write no switch for queue 0 .*/ +} semc_queuea_weight_struct_t; + +/*! @brief SEMC AXI queue a weight setting union. */ +typedef union _semc_queuea_weight +{ + semc_queuea_weight_struct_t queueaConfig; /*!< Structure configuration for queueA. */ + uint32_t queueaValue; /*!< Configuration value for queueA which could directly write to the reg. */ +} semc_queuea_weight_t; + +/*! @brief SEMC AXI queue b weight setting structure. */ +typedef struct _semc_queueb_weight_struct +{ + uint32_t qos : 4; /*!< weight of qos for queue 1. */ + uint32_t aging : 4; /*!< weight of aging for queue 1.*/ + uint32_t slaveHitSwith : 8; /*!< weight of read/write switch for queue 1.*/ + uint32_t weightPagehit : 8; /*!< weight of page hit for queue 1 only .*/ + uint32_t bankRotation : 8; /*!< weight of bank rotation for queue 1 only .*/ +} semc_queueb_weight_struct_t; + +/*! @brief SEMC AXI queue b weight setting union. */ +typedef union _semc_queueb_weight +{ + semc_queueb_weight_struct_t queuebConfig; /*!< Structure configuration for queueB. */ + uint32_t queuebValue; /*!< Configuration value for queueB which could directly write to the reg. */ +} semc_queueb_weight_t; + +/*! @brief SEMC AXI queue weight setting. */ +typedef struct _semc_axi_queueweight +{ + semc_queuea_weight_t queueaWeight; /*!< Weight settings for queue a. */ + semc_queueb_weight_t queuebWeight; /*!< Weight settings for queue b. */ +} semc_axi_queueweight_t; + +/*! + * @brief SEMC configuration structure. + * + * busTimeoutCycles: when busTimeoutCycles is zero, the bus timeout cycle is + * 255*1024. otherwise the bus timeout cycles is busTimeoutCycles*1024. + * cmdTimeoutCycles: is used for command execution timeout cycles. it's + * similar to the busTimeoutCycles. + */ +typedef struct _semc_config_t +{ + semc_dqs_mode_t dqsMode; /*!< Dummy read strobe mode: use enum in "semc_dqs_mode_t". */ + uint8_t cmdTimeoutCycles; /*!< Command execution timeout cycles. */ + uint8_t busTimeoutCycles; /*!< Bus timeout cycles. */ + semc_axi_queueweight_t queueWeight; /*!< AXI queue weight. */ +} semc_config_t; + +/******************************************************************************* + * API + ******************************************************************************/ + +#if defined(__cplusplus) +extern "C" { +#endif + +/*! + * @name SEMC Initialization and De-initialization + * @{ + */ + +/*! + * @brief Gets the SEMC default basic configuration structure. + * + * The purpose of this API is to get the default SEMC + * configure structure for SEMC_Init(). User may use the initialized + * structure unchanged in SEMC_Init(), or modify some fields of the + * structure before calling SEMC_Init(). + * Example: + @code + semc_config_t config; + SEMC_GetDefaultConfig(&config); + @endcode + * @param config The SEMC configuration structure pointer. + */ +void SEMC_GetDefaultConfig(semc_config_t *config); + +/*! + * @brief Initializes SEMC. + * This function ungates the SEMC clock and initializes SEMC. + * This function must be called before calling any other SEMC driver functions. + * + * @param base SEMC peripheral base address. + * @param configure The SEMC configuration structure pointer. + */ +void SEMC_Init(SEMC_Type *base, semc_config_t *configure); + +/*! + * @brief Deinitializes the SEMC module and gates the clock. + * + * This function gates the SEMC clock. As a result, the SEMC module doesn't work after + * calling this function, for some IDE, calling this API may cause the next downloading + * operation failed. so, please call this API cautiously. Additional, users can + * using "#define FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL (1)" to disable the clock control + * operation in drivers. + * + * @param base SEMC peripheral base address. + */ +void SEMC_Deinit(SEMC_Type *base); + +/* @} */ + +/*! + * @name SEMC Configuration Operation For Each Memory Type + * @{ + */ + +/*! + * @brief Configures SDRAM controller in SEMC. + * + * @param base SEMC peripheral base address. + * @param cs The chip selection. + * @param config The sdram configuration. + * @param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureSDRAM(SEMC_Type *base, semc_sdram_cs_t cs, semc_sdram_config_t *config, uint32_t clkSrc_Hz); + +/*! + * @brief Configures NAND controller in SEMC. + * + * @param base SEMC peripheral base address. + * @param config The nand configuration. + * @param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureNAND(SEMC_Type *base, semc_nand_config_t *config, uint32_t clkSrc_Hz); + +/*! + * @brief Configures NOR controller in SEMC. + * + * @param base SEMC peripheral base address. + * @param config The nor configuration. + * @param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureNOR(SEMC_Type *base, semc_nor_config_t *config, uint32_t clkSrc_Hz); + +/*! + * @brief Configures SRAM controller in SEMC. + * + * @param base SEMC peripheral base address. + * @param config The sram configuration. + * @param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureSRAM(SEMC_Type *base, semc_sram_config_t *config, uint32_t clkSrc_Hz); + +/*! + * @brief Configures DBI controller in SEMC. + * + * @param base SEMC peripheral base address. + * @param config The dbi configuration. + * @param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureDBI(SEMC_Type *base, semc_dbi_config_t *config, uint32_t clkSrc_Hz); + +/* @} */ + +/*! + * @name SEMC Interrupt Operation + * @{ + */ + +/*! + * @brief Enables the SEMC interrupt. + * + * This function enables the SEMC interrupts according to the provided mask. The mask + * is a logical OR of enumeration members. See @ref semc_interrupt_enable_t. + * For example, to enable the IP command done and error interrupt, do the following. + * @code + * SEMC_EnableInterrupts(ENET, kSEMC_IPCmdDoneInterrupt | kSEMC_IPCmdErrInterrupt); + * @endcode + * + * @param base SEMC peripheral base address. + * @param mask SEMC interrupts to enable. This is a logical OR of the + * enumeration :: semc_interrupt_enable_t. + */ +static inline void SEMC_EnableInterrupts(SEMC_Type *base, uint32_t mask) +{ + base->INTEN |= mask; +} + +/*! + * @brief Disables the SEMC interrupt. + * + * This function disables the SEMC interrupts according to the provided mask. The mask + * is a logical OR of enumeration members. See @ref semc_interrupt_enable_t. + * For example, to disable the IP command done and error interrupt, do the following. + * @code + * SEMC_DisableInterrupts(ENET, kSEMC_IPCmdDoneInterrupt | kSEMC_IPCmdErrInterrupt); + * @endcode + * + * @param base SEMC peripheral base address. + * @param mask SEMC interrupts to disable. This is a logical OR of the + * enumeration :: semc_interrupt_enable_t. + */ +static inline void SEMC_DisableInterrupts(SEMC_Type *base, uint32_t mask) +{ + base->INTEN &= ~mask; +} + +/*! + * @brief Gets the SEMC status. + * + * This function gets the SEMC interrupts event status. + * User can use the a logical OR of enumeration member as a mask. + * See @ref semc_interrupt_enable_t. + * + * @param base SEMC peripheral base address. + * @return status flag, use status flag in semc_interrupt_enable_t to get the related status. + */ +static inline bool SEMC_GetStatusFlag(SEMC_Type *base) +{ + return base->INTR; +} + +/*! + * @brief Clears the SEMC status flag state. + * + * The following status register flags can be cleared SEMC interrupt status. + * + * @param base SEMC base pointer + * @param mask The status flag mask, a logical OR of enumeration member @ref semc_interrupt_enable_t. + */ +static inline void SEMC_ClearStatusFlags(SEMC_Type *base, uint32_t mask) +{ + base->INTR |= mask; +} + +/* @} */ + +/*! + * @name SEMC Memory Access Operation + * @{ + */ + +/*! + * @brief Check if SEMC is in idle. + * + * @param base SEMC peripheral base address. + * @return True SEMC is in idle, false is not in idle. + */ +static inline bool SEMC_IsInIdle(SEMC_Type *base) +{ + return (base->STS0 & SEMC_STS0_IDLE_MASK) ? true : false; +} + +/*! + * @brief SEMC IP command access. + * + * @param base SEMC peripheral base address. + * @param type SEMC memory type. refer to "semc_mem_type_t" + * @param address SEMC device address. + * @param command SEMC IP command. + * For NAND device, we should use the SEMC_BuildNandIPCommand to get the right nand command. + * For NOR/DBI device, take refer to "semc_ipcmd_nor_dbi_t". + * For SRAM device, take refer to "semc_ipcmd_sram_t". + * For SDRAM device, take refer to "semc_ipcmd_sdram_t". + * @param write Data for write access. + * @param read Data pointer for read data out. + */ +status_t SEMC_SendIPCommand( + SEMC_Type *base, semc_mem_type_t type, uint32_t address, uint16_t command, uint32_t write, uint32_t *read); + +/*! + * @brief Build SEMC IP command for NAND. + * + * This function build SEMC NAND IP command. The command is build of user command code, + * SEMC address mode and SEMC command mode. + * + * @param userCommand NAND device normal command. + * @param addrMode NAND address mode. Refer to "semc_ipcmd_nand_addrmode_t". + * @param cmdMode NAND command mode. Refer to "semc_ipcmd_nand_cmdmode_t". + */ +static inline uint16_t SEMC_BuildNandIPCommand(uint8_t userCommand, + semc_ipcmd_nand_addrmode_t addrMode, + semc_ipcmd_nand_cmdmode_t cmdMode) +{ + return (uint16_t)((uint16_t)userCommand << 8) | (uint16_t)(addrMode << 4) | ((uint8_t)cmdMode & 0x0Fu); +} + +/*! + * @brief Check if the NAND device is ready. + * + * @param base SEMC peripheral base address. + * @return True NAND is ready, false NAND is not ready. + */ +static inline bool SEMC_IsNandReady(SEMC_Type *base) +{ + return (base->STS0 & SEMC_STS0_NARDY_MASK) ? true : false; +} + +/*! + * @brief SEMC NAND device memory write through IP command. + * + * @param base SEMC peripheral base address. + * @param address SEMC NAND device address. + * @param data Data for write access. + * @param size_bytes Data length. + */ +status_t SEMC_IPCommandNandWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes); + +/*! + * @brief SEMC NAND device memory read through IP command. + * + * @param base SEMC peripheral base address. + * @param address SEMC NAND device address. + * @param data Data pointer for data read out. + * @param size_bytes Data length. + */ +status_t SEMC_IPCommandNandRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes); + +/*! + * @brief SEMC NOR device memory write through IP command. + * + * @param base SEMC peripheral base address. + * @param address SEMC NOR device address. + * @param data Data for write access. + * @param size_bytes Data length. + */ +status_t SEMC_IPCommandNorWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes); + +/*! + * @brief SEMC NOR device memory read through IP command. + * + * @param base SEMC peripheral base address. + * @param address SEMC NOR device address. + * @param data Data pointer for data read out. + * @param size_bytes Data length. + */ +status_t SEMC_IPCommandNorRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes); + +/* @} */ + +#if defined(__cplusplus) +} +#endif + +/*! @}*/ + +#endif /* _FSL_SEMC_H_*/ diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Kconfig b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Kconfig new file mode 100644 index 000000000..f081299fb --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Kconfig @@ -0,0 +1,9 @@ +config BSP_USING_EXTSRAM + bool "config semc extern sram" + default n + select MEM_EXTERN_SRAM + if BSP_USING_EXTSRAM + config EXTSRAM_MAX_NUM + int "config extsram chip num" + default 4 + endif diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Makefile new file mode 100644 index 000000000..6438aa6ea --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/Makefile @@ -0,0 +1,3 @@ +SRC_FILES := connect_semc.c fsl_semc.c semc_externsdram_test.c + +include $(KERNEL_ROOT)/compiler.mk diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/connect_semc.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/connect_semc.c new file mode 100644 index 000000000..2477fb2f6 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/connect_semc.c @@ -0,0 +1,57 @@ +#include "fsl_semc.h" +#include "clock_config.h" +#include + +#define EXAMPLE_SEMC SEMC +#define EXAMPLE_SEMC_START_ADDRESS (0x80000000U) +#define EXAMPLE_SEMC_CLK_FREQ CLOCK_GetFreq(kCLOCK_SemcClk) +#define SEMC_SRAM_SIZE (32 * 1024 * 1024) + +status_t BOARD_InitSEMC(void) +{ + semc_config_t config; + semc_sdram_config_t sdramconfig; + uint32_t clockFrq = EXAMPLE_SEMC_CLK_FREQ; + + /* Initializes the MAC configure structure to zero. */ + memset(&config, 0, sizeof(semc_config_t)); + memset(&sdramconfig, 0, sizeof(semc_sdram_config_t)); + + /* Initialize SEMC. */ + SEMC_GetDefaultConfig(&config); + config.dqsMode = kSEMC_Loopbackdqspad; /* For more accurate timing. */ + SEMC_Init(SEMC, &config); + + /* Configure SDRAM. */ + sdramconfig.csxPinMux = kSEMC_MUXCSX0; + sdramconfig.address = 0x80000000; + sdramconfig.memsize_kbytes = 32 * 1024; /* 32MB = 32*1024*1KBytes*/ + sdramconfig.portSize = kSEMC_PortSize16Bit; + sdramconfig.burstLen = kSEMC_Sdram_BurstLen8; + sdramconfig.columnAddrBitNum = kSEMC_SdramColunm_9bit; + sdramconfig.casLatency = kSEMC_LatencyThree; + sdramconfig.tPrecharge2Act_Ns = 18; /* Trp 18ns */ + sdramconfig.tAct2ReadWrite_Ns = 18; /* Trcd 18ns */ + sdramconfig.tRefreshRecovery_Ns = 67; /* Use the maximum of the (Trfc , Txsr). */ + sdramconfig.tWriteRecovery_Ns = 12; /* 12ns */ + sdramconfig.tCkeOff_Ns = + 42; /* The minimum cycle of SDRAM CLK off state. CKE is off in self refresh at a minimum period tRAS.*/ + sdramconfig.tAct2Prechage_Ns = 42; /* Tras 42ns */ + sdramconfig.tSelfRefRecovery_Ns = 67; + sdramconfig.tRefresh2Refresh_Ns = 60; + sdramconfig.tAct2Act_Ns = 60; + sdramconfig.tPrescalePeriod_Ns = 160 * (1000000000 / clockFrq); + sdramconfig.refreshPeriod_nsPerRow = 64 * 1000000 / 8192; /* 64ms/8192 */ + sdramconfig.refreshUrgThreshold = sdramconfig.refreshPeriod_nsPerRow; + sdramconfig.refreshBurstLen = 1; + return SEMC_ConfigureSDRAM(SEMC, kSEMC_SDRAM_CS0, &sdramconfig, clockFrq); +} + +#ifdef BSP_USING_EXTSRAM +int ExtSramInit(void) +{ + extern void ExtSramInitBoardMemory(void *start_phy_address, void *end_phy_address, uint8 extsram_idx); + ExtSramInitBoardMemory((void*)(EXAMPLE_SEMC_START_ADDRESS), (void*)((EXAMPLE_SEMC_START_ADDRESS + SEMC_SRAM_SIZE)), kSEMC_SDRAM_CS0); + return 0; +} +#endif \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/fsl_semc.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/fsl_semc.c new file mode 100644 index 000000000..be3f225e7 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/fsl_semc.c @@ -0,0 +1,1066 @@ +/* + * Copyright 2017-2018 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "fsl_semc.h" + +/******************************************************************************* + * Definitions + ******************************************************************************/ + +/* Component ID definition, used by tools. */ +#ifndef FSL_COMPONENT_ID +#define FSL_COMPONENT_ID "platform.drivers.semc" +#endif + +/*! @brief Define macros for SEMC driver. */ +#define SEMC_IPCOMMANDDATASIZEBYTEMAX (4U) +#define SEMC_IPCOMMANDMAGICKEY (0xA55A) +#define SEMC_IOCR_PINMUXBITWIDTH (0x3U) +#define SEMC_IOCR_NAND_CE (4U) +#define SEMC_IOCR_NOR_CE (5U) +#define SEMC_IOCR_NOR_CE_A8 (2U) +#define SEMC_IOCR_PSRAM_CE (6U) +#define SEMC_IOCR_PSRAM_CE_A8 (3U) +#define SEMC_IOCR_DBI_CSX (7U) +#define SEMC_IOCR_DBI_CSX_A8 (4U) +#define SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE (24U) +#define SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX (28U) +#define SEMC_BMCR0_TYPICAL_WQOS (5U) +#define SEMC_BMCR0_TYPICAL_WAGE (8U) +#define SEMC_BMCR0_TYPICAL_WSH (0x40U) +#define SEMC_BMCR0_TYPICAL_WRWS (0x10U) +#define SEMC_BMCR1_TYPICAL_WQOS (5U) +#define SEMC_BMCR1_TYPICAL_WAGE (8U) +#define SEMC_BMCR1_TYPICAL_WPH (0x60U) +#define SEMC_BMCR1_TYPICAL_WBR (0x40U) +#define SEMC_BMCR1_TYPICAL_WRWS (0x24U) +#define SEMC_STARTADDRESS (0x80000000U) +#define SEMC_ENDADDRESS (0xDFFFFFFFU) +#define SEMC_BR_MEMSIZE_MIN (4) +#define SEMC_BR_MEMSIZE_OFFSET (2) +#define SEMC_BR_MEMSIZE_MAX (4 * 1024 * 1024) +#define SEMC_SDRAM_MODESETCAL_OFFSET (4) +#define SEMC_BR_REG_NUM (9) +#define SEMC_BYTE_NUMBIT (8) +/******************************************************************************* + * Prototypes + ******************************************************************************/ +/*! + * @brief Get instance number for SEMC module. + * + * @param base SEMC peripheral base address + */ +static uint32_t SEMC_GetInstance(SEMC_Type *base); + +/*! + * @brief Covert the input memory size to internal register set value. + * + * @param base SEMC peripheral base address + * @param size_kbytes SEMC memory size in unit of kbytes. + * @param sizeConverted SEMC converted memory size to 0 ~ 0x1F. + * @return Execution status. + */ +static status_t SEMC_CovertMemorySize(SEMC_Type *base, uint32_t size_kbytes, uint8_t *sizeConverted); + +/*! + * @brief Covert the external timing nanosecond to internal clock cycle. + * + * @param time_ns SEMC external time interval in unit of nanosecond. + * @param clkSrc_Hz SEMC clock source frequency. + * @return The changed internal clock cycle. + */ +static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz); + +/*! + * @brief Configure IP command. + * + * @param base SEMC peripheral base address. + * @param size_bytes SEMC IP command data size. + * @return Execution status. + */ +static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes); + +/*! + * @brief Check if the IP command has finished. + * + * @param base SEMC peripheral base address. + * @return Execution status. + */ +static status_t SEMC_IsIPCommandDone(SEMC_Type *base); + +/******************************************************************************* + * Variables + ******************************************************************************/ + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) +/*! @brief Pointers to SEMC clocks for each instance. */ +static const clock_ip_name_t s_semcClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_CLOCKS; +static const clock_ip_name_t s_semcExtClock[FSL_FEATURE_SOC_SEMC_COUNT] = SEMC_EXSC_CLOCKS; +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + +/*! @brief Pointers to SEMC bases for each instance. */ +static SEMC_Type *const s_semcBases[] = SEMC_BASE_PTRS; +/******************************************************************************* + * Code + ******************************************************************************/ +static uint32_t SEMC_GetInstance(SEMC_Type *base) +{ + uint32_t instance; + + /* Find the instance index from base address mappings. */ + for (instance = 0; instance < ARRAY_SIZE(s_semcBases); instance++) + { + if (s_semcBases[instance] == base) + { + break; + } + } + + assert(instance < ARRAY_SIZE(s_semcBases)); + + return instance; +} + +static status_t SEMC_CovertMemorySize(SEMC_Type *base, uint32_t size_kbytes, uint8_t *sizeConverted) +{ + assert(sizeConverted); + uint32_t memsize; + + if ((size_kbytes < SEMC_BR_MEMSIZE_MIN) || (size_kbytes > SEMC_BR_MEMSIZE_MAX)) + { + return kStatus_SEMC_InvalidMemorySize; + } + + *sizeConverted = 0; + memsize = size_kbytes / 8; + while (memsize) + { + memsize >>= 1; + (*sizeConverted)++; + } + return kStatus_Success; +} + +static uint8_t SEMC_ConvertTiming(uint32_t time_ns, uint32_t clkSrc_Hz) +{ + assert(clkSrc_Hz); + + uint8_t clockCycles = 0; + uint32_t tClk_us; + + clkSrc_Hz /= 1000000; + tClk_us = 1000000 / clkSrc_Hz; + + while (tClk_us * clockCycles < (time_ns * 1000)) + { + clockCycles++; + } + + return clockCycles; +} + +static status_t SEMC_ConfigureIPCommand(SEMC_Type *base, uint8_t size_bytes) +{ + if ((size_bytes > SEMC_IPCOMMANDDATASIZEBYTEMAX) || (!size_bytes)) + { + return kStatus_SEMC_InvalidIpcmdDataSize; + } + + /* Set data size. */ + /* Note: It is better to set data size as the device data port width when transfering + * device command data. but for device memory data transfer, it can be set freely. + * Note: If the data size is greater than data port width, for example, datsz = 4, data port = 16bit, + * then the 4-byte data transfer will be split into two 2-byte transfer, the slave address + * will be switched automatically according to connected device type*/ + base->IPCR1 = SEMC_IPCR1_DATSZ(size_bytes); + /* Clear data size. */ + base->IPCR2 = 0; + /* Set data size. */ + if (size_bytes < 4) + { + base->IPCR2 |= SEMC_IPCR2_BM3_MASK; + } + if (size_bytes < 3) + { + base->IPCR2 |= SEMC_IPCR2_BM2_MASK; + } + if (size_bytes < 2) + { + base->IPCR2 |= SEMC_IPCR2_BM1_MASK; + } + return kStatus_Success; +} + +static status_t SEMC_IsIPCommandDone(SEMC_Type *base) +{ + /* Poll status bit till command is done*/ + while (!(base->INTR & SEMC_INTR_IPCMDDONE_MASK)) + { + }; + + /* Clear status bit */ + base->INTR |= SEMC_INTR_IPCMDDONE_MASK; + + /* Check error status */ + if (base->INTR & SEMC_INTR_IPCMDERR_MASK) + { + base->INTR |= SEMC_INTR_IPCMDERR_MASK; + return kStatus_SEMC_IpCommandExecutionError; + } + + return kStatus_Success; +} + +/*! + * brief Gets the SEMC default basic configuration structure. + * + * The purpose of this API is to get the default SEMC + * configure structure for SEMC_Init(). User may use the initialized + * structure unchanged in SEMC_Init(), or modify some fields of the + * structure before calling SEMC_Init(). + * Example: + code + semc_config_t config; + SEMC_GetDefaultConfig(&config); + endcode + * param config The SEMC configuration structure pointer. + */ +void SEMC_GetDefaultConfig(semc_config_t *config) +{ + assert(config); + + /* Initializes the configure structure to zero. */ + memset(config, 0, sizeof(*config)); + + semc_queuea_weight_struct_t *queueaWeight = &(config->queueWeight.queueaWeight.queueaConfig); + semc_queueb_weight_struct_t *queuebWeight = &(config->queueWeight.queuebWeight.queuebConfig); + + /* Get default settings. */ + config->dqsMode = kSEMC_Loopbackinternal; + config->cmdTimeoutCycles = 0; + config->busTimeoutCycles = 0x1F; + + queueaWeight->qos = SEMC_BMCR0_TYPICAL_WQOS; + queueaWeight->aging = SEMC_BMCR0_TYPICAL_WAGE; + queueaWeight->slaveHitSwith = SEMC_BMCR0_TYPICAL_WSH; + queueaWeight->slaveHitNoswitch = SEMC_BMCR0_TYPICAL_WRWS; + queuebWeight->qos = SEMC_BMCR1_TYPICAL_WQOS; + queuebWeight->aging = SEMC_BMCR1_TYPICAL_WAGE; + queuebWeight->slaveHitSwith = SEMC_BMCR1_TYPICAL_WRWS; + queuebWeight->weightPagehit = SEMC_BMCR1_TYPICAL_WPH; + queuebWeight->bankRotation = SEMC_BMCR1_TYPICAL_WBR; +} + +/*! + * brief Initializes SEMC. + * This function ungates the SEMC clock and initializes SEMC. + * This function must be called before calling any other SEMC driver functions. + * + * param base SEMC peripheral base address. + * param configure The SEMC configuration structure pointer. + */ +void SEMC_Init(SEMC_Type *base, semc_config_t *configure) +{ + assert(configure); + + uint8_t index = 0; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Un-gate sdram controller clock. */ + CLOCK_EnableClock(s_semcClock[SEMC_GetInstance(base)]); + CLOCK_EnableClock(s_semcExtClock[SEMC_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ + + /* Initialize all BR to zero due to the default base address set. */ + for (index = 0; index < SEMC_BR_REG_NUM; index++) + { + base->BR[index] = 0; + } + + /* Software reset for SEMC internal logical . */ + base->MCR = SEMC_MCR_SWRST_MASK; + while (base->MCR & SEMC_MCR_SWRST_MASK) + { + } + + /* Configure, disable module first. */ + base->MCR |= SEMC_MCR_MDIS_MASK | SEMC_MCR_BTO(configure->busTimeoutCycles) | + SEMC_MCR_CTO(configure->cmdTimeoutCycles) | SEMC_MCR_DQSMD(configure->dqsMode); + + /* Configure Queue 0/1 for AXI bus. */ + base->BMCR0 = (uint32_t)(configure->queueWeight.queueaWeight.queueaValue); + base->BMCR1 = (uint32_t)(configure->queueWeight.queuebWeight.queuebValue); + + /* Enable SEMC. */ + base->MCR &= ~SEMC_MCR_MDIS_MASK; +} + +/*! + * brief Deinitializes the SEMC module and gates the clock. + * This function gates the SEMC clock. As a result, the SEMC + * module doesn't work after calling this function. + * + * param base SEMC peripheral base address. + */ +void SEMC_Deinit(SEMC_Type *base) +{ + /* Disable module. Check there is no pending command before disable module. */ + while (!(base->STS0 & SEMC_STS0_IDLE_MASK)) + { + ; + } + + base->MCR |= SEMC_MCR_MDIS_MASK | SEMC_MCR_SWRST_MASK; + +#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) + /* Disable SDRAM clock. */ + CLOCK_DisableClock(s_semcClock[SEMC_GetInstance(base)]); + CLOCK_DisableClock(s_semcExtClock[SEMC_GetInstance(base)]); +#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */ +} + +/*! + * brief Configures SDRAM controller in SEMC. + * + * param base SEMC peripheral base address. + * param cs The chip selection. + * param config The sdram configuration. + * param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureSDRAM(SEMC_Type *base, semc_sdram_cs_t cs, semc_sdram_config_t *config, uint32_t clkSrc_Hz) +{ + assert(config); + assert(clkSrc_Hz); + assert(config->refreshBurstLen); + + uint8_t memsize; + status_t result = kStatus_Success; + uint16_t prescale = config->tPrescalePeriod_Ns / 16 / (1000000000 / clkSrc_Hz); + uint16_t refresh; + uint16_t urgentRef; + uint16_t idle; + uint16_t mode; + + if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) + { + return kStatus_SEMC_InvalidBaseAddress; + } + + if (config->csxPinMux == kSEMC_MUXA8) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + + if (prescale > 256) + { + return kStatus_SEMC_InvalidTimerSetting; + } + + refresh = config->refreshPeriod_nsPerRow / config->tPrescalePeriod_Ns; + urgentRef = config->refreshUrgThreshold / config->tPrescalePeriod_Ns; + idle = config->tIdleTimeout_Ns / config->tPrescalePeriod_Ns; + + uint32_t iocReg = base->IOCR & ~(SEMC_IOCR_PINMUXBITWIDTH << config->csxPinMux); + + /* Base control. */ + result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); + if (result != kStatus_Success) + { + return result; + } + + base->BR[cs] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; + base->SDRAMCR0 = SEMC_SDRAMCR0_PS(config->portSize) | SEMC_SDRAMCR0_BL(config->burstLen) | + SEMC_SDRAMCR0_COL(config->columnAddrBitNum) | SEMC_SDRAMCR0_CL(config->casLatency); + /* IOMUX setting. */ + if (cs) + { + base->IOCR = iocReg | (cs << config->csxPinMux); + } + + base->IOCR &= ~SEMC_IOCR_MUX_A8_MASK; + + /* Timing setting. */ + base->SDRAMCR1 = SEMC_SDRAMCR1_PRE2ACT(SEMC_ConvertTiming(config->tPrecharge2Act_Ns, clkSrc_Hz) - 1) | + SEMC_SDRAMCR1_ACT2RW(SEMC_ConvertTiming(config->tAct2ReadWrite_Ns, clkSrc_Hz) - 1) | + SEMC_SDRAMCR1_RFRC(SEMC_ConvertTiming(config->tRefreshRecovery_Ns, clkSrc_Hz) - 1) | + SEMC_SDRAMCR1_WRC(SEMC_ConvertTiming(config->tWriteRecovery_Ns, clkSrc_Hz) - 1) | + SEMC_SDRAMCR1_CKEOFF(SEMC_ConvertTiming(config->tCkeOff_Ns, clkSrc_Hz) - 1) | + SEMC_SDRAMCR1_ACT2PRE(SEMC_ConvertTiming(config->tAct2Prechage_Ns, clkSrc_Hz) - 1); + base->SDRAMCR2 = + SEMC_SDRAMCR2_SRRC(SEMC_ConvertTiming(config->tSelfRefRecovery_Ns, clkSrc_Hz) - 1) | + SEMC_SDRAMCR2_REF2REF( + SEMC_ConvertTiming(config->tRefresh2Refresh_Ns, clkSrc_Hz)) | /* No Minus one to keep with RM */ + SEMC_SDRAMCR2_ACT2ACT(SEMC_ConvertTiming(config->tAct2Act_Ns, clkSrc_Hz)) | /* No Minus one to keep with RM */ + SEMC_SDRAMCR2_ITO(idle); + base->SDRAMCR3 = SEMC_SDRAMCR3_REBL(config->refreshBurstLen - 1) | + /* N * 16 * 1s / clkSrc_Hz = config->tPrescalePeriod_Ns */ + SEMC_SDRAMCR3_PRESCALE(prescale) | SEMC_SDRAMCR3_RT(refresh) | SEMC_SDRAMCR3_UT(urgentRef); + + SEMC->IPCR1 = 0x2; + SEMC->IPCR2 = 0; + + result = SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, kSEMC_SDRAMCM_Prechargeall, 0, NULL); + if (result != kStatus_Success) + { + return result; + } + result = SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, kSEMC_SDRAMCM_AutoRefresh, 0, NULL); + if (result != kStatus_Success) + { + return result; + } + result = SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, kSEMC_SDRAMCM_AutoRefresh, 0, NULL); + if (result != kStatus_Success) + { + return result; + } + /* Mode setting value. */ + mode = (uint16_t)config->burstLen | (uint16_t)(config->casLatency << SEMC_SDRAM_MODESETCAL_OFFSET); + result = SEMC_SendIPCommand(base, kSEMC_MemType_SDRAM, config->address, kSEMC_SDRAMCM_Modeset, mode, NULL); + if (result != kStatus_Success) + { + return result; + } + /* Enables refresh */ + base->SDRAMCR3 |= SEMC_SDRAMCR3_REN_MASK; + + return kStatus_Success; +} + +/*! + * brief Configures NAND controller in SEMC. + * + * param base SEMC peripheral base address. + * param config The nand configuration. + * param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureNAND(SEMC_Type *base, semc_nand_config_t *config, uint32_t clkSrc_Hz) +{ + assert(config); + assert(config->timingConfig); + + uint8_t memsize; + status_t result; + + if ((config->axiAddress < SEMC_STARTADDRESS) || (config->axiAddress > SEMC_ENDADDRESS)) + { + return kStatus_SEMC_InvalidBaseAddress; + } + + if (config->cePinMux == kSEMC_MUXRDY) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + + uint32_t iocReg = base->IOCR & ~((SEMC_IOCR_PINMUXBITWIDTH << config->cePinMux) | SEMC_IOCR_MUX_RDY_MASK); + + /* Base control. */ + if (config->rdyactivePolarity == kSEMC_RdyActivehigh) + { + base->MCR |= SEMC_MCR_WPOL1_MASK; + } + else + { + base->MCR &= ~SEMC_MCR_WPOL1_MASK; + } + result = SEMC_CovertMemorySize(base, config->axiMemsize_kbytes, &memsize); + if (result != kStatus_Success) + { + return result; + } + base->BR[4] = (config->axiAddress & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; + + result = SEMC_CovertMemorySize(base, config->ipgMemsize_kbytes, &memsize); + if (result != kStatus_Success) + { + return result; + } + base->BR[8] = (config->ipgAddress & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; + + /* IOMUX setting. */ + if (config->cePinMux) + { + base->IOCR = iocReg | (SEMC_IOCR_NAND_CE << config->cePinMux); + } + else + { + base->IOCR = iocReg | (1U << config->cePinMux); + } + + base->NANDCR0 = SEMC_NANDCR0_PS(config->portSize) | SEMC_NANDCR0_BL(config->burstLen) | + SEMC_NANDCR0_EDO(config->edoModeEnabled) | SEMC_NANDCR0_COL(config->columnAddrBitNum); + + /* Timing setting. */ + base->NANDCR1 = SEMC_NANDCR1_CES(SEMC_ConvertTiming(config->timingConfig->tCeSetup_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_CEH(SEMC_ConvertTiming(config->timingConfig->tCeHold_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_WEL(SEMC_ConvertTiming(config->timingConfig->tWeLow_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_WEH(SEMC_ConvertTiming(config->timingConfig->tWeHigh_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_REL(SEMC_ConvertTiming(config->timingConfig->tReLow_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_REH(SEMC_ConvertTiming(config->timingConfig->tReHigh_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_TA(SEMC_ConvertTiming(config->timingConfig->tTurnAround_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR1_CEITV(SEMC_ConvertTiming(config->timingConfig->tCeInterval_Ns, clkSrc_Hz) - 1); + base->NANDCR2 = SEMC_NANDCR2_TWHR(SEMC_ConvertTiming(config->timingConfig->tWehigh2Relow_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR2_TRHW(SEMC_ConvertTiming(config->timingConfig->tRehigh2Welow_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR2_TADL(SEMC_ConvertTiming(config->timingConfig->tAle2WriteStart_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR2_TRR(SEMC_ConvertTiming(config->timingConfig->tReady2Relow_Ns, clkSrc_Hz) - 1) | + SEMC_NANDCR2_TWB(SEMC_ConvertTiming(config->timingConfig->tWehigh2Busy_Ns, clkSrc_Hz) - 1); + base->NANDCR3 = config->arrayAddrOption; + return kStatus_Success; +} + +/*! + * brief Configures NOR controller in SEMC. + * + * param base SEMC peripheral base address. + * param config The nor configuration. + * param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureNOR(SEMC_Type *base, semc_nor_config_t *config, uint32_t clkSrc_Hz) +{ + assert(config); + + uint8_t memsize; + status_t result; + + if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) + { + return kStatus_SEMC_InvalidBaseAddress; + } + + uint32_t iocReg = base->IOCR & ~(SEMC_IOCR_PINMUXBITWIDTH << config->cePinMux); + uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ? + SEMC_IOCR_NOR_CE - 1 : + ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_NOR_CE_A8 : SEMC_IOCR_NOR_CE); + + /* IOMUX setting. */ + base->IOCR = iocReg | (muxCe << config->cePinMux); + /* Address bit setting. */ + if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE) + { + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1) + { + /* Address bit 24 (A24) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX0_MASK; + if (config->cePinMux == kSEMC_MUXCSX0) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 2) + { + /* Address bit 25 (A25) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX1_MASK; + if (config->cePinMux == kSEMC_MUXCSX1) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 3) + { + /* Address bit 26 (A26) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX2_MASK; + if (config->cePinMux == kSEMC_MUXCSX2) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 4) + { + if (config->addr27 == kSEMC_NORA27_MUXCSX3) + { + /* Address bit 27 (A27) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX3_MASK; + } + else if (config->addr27 == kSEMC_NORA27_MUXRDY) + { + base->IOCR |= SEMC_IOCR_MUX_RDY_MASK; + } + else + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + if (config->cePinMux == kSEMC_MUXCSX3) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX) + { + return kStatus_SEMC_InvalidAddressPortWidth; + } + } + + /* Base control. */ + if (config->rdyactivePolarity == kSEMC_RdyActivehigh) + { + base->MCR |= SEMC_MCR_WPOL0_MASK; + } + else + { + base->MCR &= ~SEMC_MCR_WPOL0_MASK; + } + result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); + if (result != kStatus_Success) + { + return result; + } + base->BR[5] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; + base->NORCR0 = SEMC_NORCR0_PS(config->portSize) | SEMC_NORCR0_BL(config->burstLen) | + SEMC_NORCR0_AM(config->addrMode) | SEMC_NORCR0_ADVP(config->advActivePolarity) | + SEMC_NORCR0_COL(config->columnAddrBitNum); + + /* Timing setting. */ + base->NORCR1 = SEMC_NORCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz)) | + SEMC_NORCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz)) | + SEMC_NORCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz)) | + SEMC_NORCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz)) | + SEMC_NORCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz)) | + SEMC_NORCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz)) | + SEMC_NORCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz)) | + SEMC_NORCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz)); + base->NORCR2 = +#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME) + SEMC_NORCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz)) | +#endif /* FSL_FEATURE_SEMC_HAS_NOR_WDS_TIME */ +#if defined(FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) && (FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME) + SEMC_NORCR2_WDH(SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz)) | +#endif /* FSL_FEATURE_SEMC_HAS_NOR_WDH_TIME */ + SEMC_NORCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz)) | + SEMC_NORCR2_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz) + 1) | + SEMC_NORCR2_LC(config->latencyCount) | SEMC_NORCR2_RD(config->readCycle) | + SEMC_NORCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz)); + + return SEMC_ConfigureIPCommand(base, (config->portSize + 1)); +} + +/*! + * brief Configures SRAM controller in SEMC. + * + * param base SEMC peripheral base address. + * param config The sram configuration. + * param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureSRAM(SEMC_Type *base, semc_sram_config_t *config, uint32_t clkSrc_Hz) +{ + assert(config); + + uint8_t memsize; + status_t result = kStatus_Success; + + if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) + { + return kStatus_SEMC_InvalidBaseAddress; + } + + uint32_t iocReg = base->IOCR & ~(SEMC_IOCR_PINMUXBITWIDTH << config->cePinMux); + uint32_t muxCe = (config->cePinMux == kSEMC_MUXRDY) ? + SEMC_IOCR_PSRAM_CE - 1 : + ((config->cePinMux == kSEMC_MUXA8) ? SEMC_IOCR_PSRAM_CE_A8 : SEMC_IOCR_PSRAM_CE); + + /* IOMUX setting. */ + base->IOCR = iocReg | (muxCe << config->cePinMux); + /* Address bit setting. */ + if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE) + { + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 1) + { + /* Address bit 24 (A24) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX0_MASK; + if (config->cePinMux == kSEMC_MUXCSX0) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 2) + { + /* Address bit 25 (A25) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX1_MASK; + if (config->cePinMux == kSEMC_MUXCSX1) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 3) + { + /* Address bit 26 (A26) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX2_MASK; + if (config->cePinMux == kSEMC_MUXCSX2) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth >= SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHBASE + 4) + { + if (config->addr27 == kSEMC_NORA27_MUXCSX3) + { + /* Address bit 27 (A27) */ + base->IOCR &= (uint32_t)~SEMC_IOCR_MUX_CSX3_MASK; + } + else if (config->addr27 == kSEMC_NORA27_MUXRDY) + { + base->IOCR |= SEMC_IOCR_MUX_RDY_MASK; + } + else + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + + if (config->cePinMux == kSEMC_MUXCSX3) + { + return kStatus_SEMC_InvalidSwPinmuxSelection; + } + } + if (config->addrPortWidth > SEMC_NORFLASH_SRAM_ADDR_PORTWIDTHMAX) + { + return kStatus_SEMC_InvalidAddressPortWidth; + } + } + /* Base control. */ + result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); + if (result != kStatus_Success) + { + return result; + } + base->BR[6] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; + base->SRAMCR0 = SEMC_SRAMCR0_PS(config->portSize) | SEMC_SRAMCR0_BL(config->burstLen) | + SEMC_SRAMCR0_AM(config->addrMode) | SEMC_SRAMCR0_ADVP(config->advActivePolarity) | + SEMC_SRAMCR0_COL_MASK; + + /* Timing setting. */ + base->SRAMCR1 = SEMC_SRAMCR1_CES(SEMC_ConvertTiming(config->tCeSetup_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_CEH(SEMC_ConvertTiming(config->tCeHold_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_AS(SEMC_ConvertTiming(config->tAddrSetup_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_AH(SEMC_ConvertTiming(config->tAddrHold_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_WEL(SEMC_ConvertTiming(config->tWeLow_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_WEH(SEMC_ConvertTiming(config->tWeHigh_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_REL(SEMC_ConvertTiming(config->tReLow_Ns, clkSrc_Hz)) | + SEMC_SRAMCR1_REH(SEMC_ConvertTiming(config->tReHigh_Ns, clkSrc_Hz)); + + base->SRAMCR2 = SEMC_SRAMCR2_WDS(SEMC_ConvertTiming(config->tWriteSetup_Ns, clkSrc_Hz)) | + SEMC_SRAMCR2_WDH(SEMC_ConvertTiming(config->tWriteHold_Ns, clkSrc_Hz)) | + SEMC_SRAMCR2_TA(SEMC_ConvertTiming(config->tTurnAround_Ns, clkSrc_Hz)) | + SEMC_SRAMCR2_AWDH(SEMC_ConvertTiming(config->tAddr2WriteHold_Ns, clkSrc_Hz) + 1) | + SEMC_SRAMCR2_LC(config->latencyCount) | SEMC_SRAMCR2_RD(config->readCycle) | + SEMC_SRAMCR2_CEITV(SEMC_ConvertTiming(config->tCeInterval_Ns, clkSrc_Hz)); + + return result; +} + +/*! + * brief Configures DBI controller in SEMC. + * + * param base SEMC peripheral base address. + * param config The dbi configuration. + * param clkSrc_Hz The SEMC clock frequency. + */ +status_t SEMC_ConfigureDBI(SEMC_Type *base, semc_dbi_config_t *config, uint32_t clkSrc_Hz) +{ + assert(config); + + uint8_t memsize; + status_t result; + + if ((config->address < SEMC_STARTADDRESS) || (config->address > SEMC_ENDADDRESS)) + { + return kStatus_SEMC_InvalidBaseAddress; + } + + uint32_t iocReg = base->IOCR & ~(SEMC_IOCR_PINMUXBITWIDTH << config->csxPinMux); + uint32_t muxCsx = (config->csxPinMux == kSEMC_MUXRDY) ? + SEMC_IOCR_DBI_CSX - 1 : + ((config->csxPinMux == kSEMC_MUXA8) ? SEMC_IOCR_DBI_CSX_A8 : SEMC_IOCR_DBI_CSX); + + /* IOMUX setting. */ + base->IOCR = iocReg | (muxCsx << config->csxPinMux); + /* Base control. */ + result = SEMC_CovertMemorySize(base, config->memsize_kbytes, &memsize); + if (result != kStatus_Success) + { + return result; + } + base->BR[7] = (config->address & SEMC_BR_BA_MASK) | SEMC_BR_MS(memsize) | SEMC_BR_VLD_MASK; + base->DBICR0 = + SEMC_DBICR0_PS(config->portSize) | SEMC_DBICR0_BL(config->burstLen) | SEMC_DBICR0_COL(config->columnAddrBitNum); + + /* Timing setting. */ + base->DBICR1 = SEMC_DBICR1_CES(SEMC_ConvertTiming(config->tCsxSetup_Ns, clkSrc_Hz) - 1) | + SEMC_DBICR1_CEH(SEMC_ConvertTiming(config->tCsxHold_Ns, clkSrc_Hz) - 1) | + SEMC_DBICR1_WEL(SEMC_ConvertTiming(config->tWexLow_Ns, clkSrc_Hz) - 1) | + SEMC_DBICR1_WEH(SEMC_ConvertTiming(config->tWexHigh_Ns, clkSrc_Hz) - 1) | + SEMC_DBICR1_REL(SEMC_ConvertTiming(config->tRdxLow_Ns, clkSrc_Hz) - 1) | + SEMC_DBICR1_REH(SEMC_ConvertTiming(config->tRdxHigh_Ns, clkSrc_Hz) - 1) | + SEMC_DBICR1_CEITV(SEMC_ConvertTiming(config->tCsxInterval_Ns, clkSrc_Hz) - 1); + return SEMC_ConfigureIPCommand(base, (config->portSize + 1)); +} + +/*! + * brief SEMC IP command access. + * + * param base SEMC peripheral base address. + * param type SEMC memory type. refer to "semc_mem_type_t" + * param address SEMC device address. + * param command SEMC IP command. + * For NAND device, we should use the SEMC_BuildNandIPCommand to get the right nand command. + * For NOR/DBI device, take refer to "semc_ipcmd_nor_dbi_t". + * For SRAM device, take refer to "semc_ipcmd_sram_t". + * For SDRAM device, take refer to "semc_ipcmd_sdram_t". + * param write Data for write access. + * param read Data pointer for read data out. + */ +status_t SEMC_SendIPCommand( + SEMC_Type *base, semc_mem_type_t type, uint32_t address, uint16_t command, uint32_t write, uint32_t *read) +{ + uint32_t cmdMode; + bool readCmd = 0; + bool writeCmd = 0; + status_t result; + + /* Clear status bit */ + base->INTR |= SEMC_INTR_IPCMDDONE_MASK; + /* Set address. */ + base->IPCR0 = address; + + /* Check command mode. */ + cmdMode = command & 0xFU; + switch (type) + { + case kSEMC_MemType_NAND: + readCmd = (cmdMode == kSEMC_NANDCM_CommandAddressRead) || (cmdMode == kSEMC_NANDCM_CommandRead) || + (cmdMode == kSEMC_NANDCM_Read); + writeCmd = (cmdMode == kSEMC_NANDCM_CommandAddressWrite) || (cmdMode == kSEMC_NANDCM_CommandWrite) || + (cmdMode == kSEMC_NANDCM_Write); + break; + case kSEMC_MemType_NOR: + case kSEMC_MemType_8080: + readCmd = (cmdMode == kSEMC_NORDBICM_Read); + writeCmd = (cmdMode == kSEMC_NORDBICM_Write); + break; + case kSEMC_MemType_SRAM: + readCmd = (cmdMode == kSEMC_SRAMCM_ArrayRead) || (cmdMode == kSEMC_SRAMCM_RegRead); + writeCmd = (cmdMode == kSEMC_SRAMCM_ArrayWrite) || (cmdMode == kSEMC_SRAMCM_RegWrite); + break; + case kSEMC_MemType_SDRAM: + readCmd = (cmdMode == kSEMC_SDRAMCM_Read); + writeCmd = (cmdMode == kSEMC_SDRAMCM_Write) || (cmdMode == kSEMC_SDRAMCM_Modeset); + break; + default: + break; + } + + if (writeCmd) + { + /* Set data. */ + base->IPTXDAT = write; + } + + /* Set command code. */ + base->IPCMD = command | SEMC_IPCMD_KEY(SEMC_IPCOMMANDMAGICKEY); + /* Wait for command done. */ + result = SEMC_IsIPCommandDone(base); + if (result != kStatus_Success) + { + return result; + } + + if (readCmd) + { + /* Get the read data */ + *read = base->IPRXDAT; + } + + return kStatus_Success; +} + +/*! + * brief SEMC NAND device memory write through IP command. + * + * param base SEMC peripheral base address. + * param address SEMC NAND device address. + * param data Data for write access. + * param size_bytes Data length. + */ +status_t SEMC_IPCommandNandWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) +{ + assert(data); + + status_t result = kStatus_Success; + uint16_t ipCmd; + uint32_t tempData = 0; + + /* Write command built */ + ipCmd = SEMC_BuildNandIPCommand(0, kSEMC_NANDAM_ColumnRow, kSEMC_NANDCM_Write); + while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) + { + /* Configure IP command data size. */ + SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); + result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, *(uint32_t *)data, NULL); + if (result != kStatus_Success) + { + break; + } + + data += SEMC_IPCOMMANDDATASIZEBYTEMAX; + size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; + } + + if ((result == kStatus_Success) && size_bytes) + { + SEMC_ConfigureIPCommand(base, size_bytes); + + while (size_bytes) + { + tempData |= ((uint32_t) * (data + size_bytes - 1) << ((size_bytes - 1) * SEMC_BYTE_NUMBIT)); + size_bytes--; + } + + result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, tempData, NULL); + } + + return result; +} + +/*! + * brief SEMC NAND device memory read through IP command. + * + * param base SEMC peripheral base address. + * param address SEMC NAND device address. + * param data Data pointer for data read out. + * param size_bytes Data length. + */ +status_t SEMC_IPCommandNandRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) +{ + assert(data); + + status_t result = kStatus_Success; + uint16_t ipCmd; + uint32_t tempData = 0; + + /* Configure IP command data size. */ + SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); + /* Read command built */ + ipCmd = SEMC_BuildNandIPCommand(0, kSEMC_NANDAM_ColumnRow, kSEMC_NANDCM_Read); + + while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) + { + result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, (uint32_t *)data); + if (result != kStatus_Success) + { + break; + } + + data += SEMC_IPCOMMANDDATASIZEBYTEMAX; + size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; + } + + if ((result == kStatus_Success) && size_bytes) + { + SEMC_ConfigureIPCommand(base, size_bytes); + result = SEMC_SendIPCommand(base, kSEMC_MemType_NAND, address, ipCmd, 0, &tempData); + + while (size_bytes) + { + size_bytes--; + *(data + size_bytes) = (tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU; + } + } + + return result; +} + +/*! + * brief SEMC NOR device memory read through IP command. + * + * param base SEMC peripheral base address. + * param address SEMC NOR device address. + * param data Data pointer for data read out. + * param size_bytes Data length. + */ +status_t SEMC_IPCommandNorRead(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) +{ + assert(data); + + uint32_t tempData = 0; + status_t result = kStatus_Success; + uint8_t dataSize = base->NORCR0 & SEMC_NORCR0_PS_MASK; + + /* Configure IP command data size. */ + SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); + + while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) + { + result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, kSEMC_NORDBICM_Read, 0, (uint32_t *)data); + if (result != kStatus_Success) + { + break; + } + + data += SEMC_IPCOMMANDDATASIZEBYTEMAX; + size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; + } + + if ((result == kStatus_Success) && size_bytes) + { + SEMC_ConfigureIPCommand(base, size_bytes); + result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, kSEMC_NORDBICM_Read, 0, &tempData); + while (size_bytes) + { + size_bytes--; + *(data + size_bytes) = (tempData >> (SEMC_BYTE_NUMBIT * size_bytes)) & 0xFFU; + } + } + + SEMC_ConfigureIPCommand(base, dataSize); + return result; +} + +/*! + * brief SEMC NOR device memory write through IP command. + * + * param base SEMC peripheral base address. + * param address SEMC NOR device address. + * param data Data for write access. + * param size_bytes Data length. + */ +status_t SEMC_IPCommandNorWrite(SEMC_Type *base, uint32_t address, uint8_t *data, uint32_t size_bytes) +{ + assert(data); + + uint32_t tempData = 0; + status_t result = kStatus_Success; + uint8_t dataSize = base->NORCR0 & SEMC_NORCR0_PS_MASK; + + /* Write command built */ + while (size_bytes >= SEMC_IPCOMMANDDATASIZEBYTEMAX) + { + /* Configure IP command data size. */ + SEMC_ConfigureIPCommand(base, SEMC_IPCOMMANDDATASIZEBYTEMAX); + result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, kSEMC_NORDBICM_Write, *(uint32_t *)data, NULL); + if (result != kStatus_Success) + { + break; + } + size_bytes -= SEMC_IPCOMMANDDATASIZEBYTEMAX; + data += SEMC_IPCOMMANDDATASIZEBYTEMAX; + } + + if ((result == kStatus_Success) && size_bytes) + { + SEMC_ConfigureIPCommand(base, size_bytes); + + while (size_bytes) + { + tempData |= ((uint32_t) * (data + size_bytes - 1) << ((size_bytes - 1) * SEMC_BYTE_NUMBIT)); + size_bytes--; + } + + result = SEMC_SendIPCommand(base, kSEMC_MemType_NOR, address, kSEMC_NORDBICM_Write, tempData, NULL); + } + SEMC_ConfigureIPCommand(base, dataSize); + + return result; +} diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/semc_externsdram_test.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/semc_externsdram_test.c new file mode 100644 index 000000000..c09b6dc27 --- /dev/null +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/semc/semc_externsdram_test.c @@ -0,0 +1,180 @@ +/* + * Copyright 2017 NXP + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include "board.h" + +#define EXAMPLE_SEMC_START_ADDRESS (0x80000000U) + +#define SEMC_EXAMPLE_DATALEN (0x1000U) + +/******************************************************************************* + * Prototypes + ******************************************************************************/ +static void SEMC_SDRAMReadWrite32Bit(void); +static void SEMC_SDRAMReadWrite16Bit(void); +static void SEMC_SDRAMReadWrite8Bit(void); +/******************************************************************************* + * Variables + ******************************************************************************/ + +uint32_t sdram_writeBuffer[SEMC_EXAMPLE_DATALEN]; +uint32_t sdram_readBuffer[SEMC_EXAMPLE_DATALEN]; + +/*! + * @brief Main function + */ +int semc_externsram_test(void) +{ + KPrintf("\r\n SEMC SDRAM Example Start!\r\n"); + + /* 32Bit data read and write. */ + SEMC_SDRAMReadWrite32Bit(); + /* 16Bit data read and write. */ + SEMC_SDRAMReadWrite16Bit(); + /* 8Bit data read and write. */ + SEMC_SDRAMReadWrite8Bit(); + + KPrintf("\r\n SEMC SDRAM Example End.\r\n"); + +} +SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0),semc_externsram_test, semc_externsram_test, semc_externsram_test ); + +void SEMC_SDRAMReadWrite32Bit(void) +{ + uint32_t index; + uint32_t datalen = SEMC_EXAMPLE_DATALEN; + uint32_t *sdram = (uint32_t *)EXAMPLE_SEMC_START_ADDRESS; /* SDRAM start address. */ + int result = 0; + + KPrintf("\r\n SEMC SDRAM Memory 32 bit Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen); + /* Prepare data and write to SDRAM. */ + for (index = 0; index < datalen; index++) + { + sdram_writeBuffer[index] = index; + sdram[index] = sdram_writeBuffer[index]; + } + + KPrintf("\r\n SEMC SDRAM Read 32 bit Data Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen); + /* Read data from the SDRAM. */ + for (index = 0; index < datalen; index++) + { + sdram_readBuffer[index] = sdram[index]; + } + + KPrintf("\r\n SEMC SDRAM 32 bit Data Write and Read Compare Start!\r\n"); + /* Compare the two buffers. */ + while (datalen--) + { + if (sdram_writeBuffer[datalen] != sdram_readBuffer[datalen]) + { + result = -1; + break; + } + } + + if (result < 0) + { + KPrintf("\r\n SEMC SDRAM 32 bit Data Write and Read Compare Failed!\r\n"); + } + else + { + KPrintf("\r\n SEMC SDRAM 32 bit Data Write and Read Compare Succeed!\r\n"); + } +} + +static void SEMC_SDRAMReadWrite16Bit(void) +{ + uint32_t index; + uint32_t datalen = SEMC_EXAMPLE_DATALEN; + uint16_t *sdram = (uint16_t *)EXAMPLE_SEMC_START_ADDRESS; /* SDRAM start address. */ + int result = 0; + + KPrintf("\r\n SEMC SDRAM Memory 16 bit Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen); + + memset(sdram_writeBuffer, 0, sizeof(sdram_writeBuffer)); + memset(sdram_readBuffer, 0, sizeof(sdram_readBuffer)); + + /* Prepare data and write to SDRAM. */ + for (index = 0; index < datalen; index++) + { + sdram_writeBuffer[index] = index % 0xFFFF; + sdram[index] = sdram_writeBuffer[index]; + } + + KPrintf("\r\n SEMC SDRAM Read 16 bit Data Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen); + /* Read data from the SDRAM. */ + for (index = 0; index < datalen; index++) + { + sdram_readBuffer[index] = sdram[index]; + } + + KPrintf("\r\n SEMC SDRAM 16 bit Data Write and Read Compare Start!\r\n"); + /* Compare the two buffers. */ + while (datalen--) + { + if (sdram_writeBuffer[datalen] != sdram_readBuffer[datalen]) + { + result = -1; + break; + } + } + + if (result < 0) + { + KPrintf("\r\n SEMC SDRAM 16 bit Data Write and Read Compare Failed!\r\n"); + } + else + { + KPrintf("\r\n SEMC SDRAM 16 bit Data Write and Read Compare Succeed!\r\n"); + } +} + +static void SEMC_SDRAMReadWrite8Bit(void) +{ + uint32_t index; + uint32_t datalen = SEMC_EXAMPLE_DATALEN; + uint8_t *sdram = (uint8_t *)EXAMPLE_SEMC_START_ADDRESS; /* SDRAM start address. */ + int result = 0; + + KPrintf("\r\n SEMC SDRAM Memory 8 bit Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen); + + memset(sdram_writeBuffer, 0, sizeof(sdram_writeBuffer)); + memset(sdram_readBuffer, 0, sizeof(sdram_readBuffer)); + + /* Prepare data and write to SDRAM. */ + for (index = 0; index < datalen; index++) + { + sdram_writeBuffer[index] = index % 0x100; + sdram[index] = sdram_writeBuffer[index]; + } + + KPrintf("\r\n SEMC SDRAM Read 8 bit Data Start, Start Address 0x%x, Data Length %d !\r\n", sdram, datalen); + /* Read data from the SDRAM. */ + for (index = 0; index < datalen; index++) + { + sdram_readBuffer[index] = sdram[index]; + } + + KPrintf("\r\n SEMC SDRAM 8 bit Data Write and Read Compare Start!\r\n"); + /* Compare the two buffers. */ + while (datalen--) + { + if (sdram_writeBuffer[datalen] != sdram_readBuffer[datalen]) + { + result = -1; + break; + } + } + + if (result < 0) + { + KPrintf("\r\n SEMC SDRAM 8 bit Data Write and Read Compare Failed!\r\n"); + } + else + { + KPrintf("\r\n SEMC SDRAM 8 bit Data Write and Read Compare Succeed!\r\n"); + } +} diff --git a/Ubiquitous/XiZi/path_kernel.mk b/Ubiquitous/XiZi/path_kernel.mk index 2bdbb01f0..3696e2a4b 100755 --- a/Ubiquitous/XiZi/path_kernel.mk +++ b/Ubiquitous/XiZi/path_kernel.mk @@ -13,10 +13,21 @@ KERNELPATHS :=-I$(BSP_ROOT) \ -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/include \ -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/osa \ -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/phy \ + -I$(BSP_ROOT)/third_party_driver/ethernet \ + -I$(BSP_ROOT)/third_party_driver/ethernet/ksz8081 \ -I$(BSP_ROOT)/third_party_driver/MIMXRT1052 \ -I$(BSP_ROOT)/third_party_driver/MIMXRT1052/drivers \ -I$(BSP_ROOT)/third_party_driver/CMSIS/Include \ -I$(KERNEL_ROOT)/include \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/compat \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/netif \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip/apps \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip/priv \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/include/lwip/prot \ + -I$(KERNEL_ROOT)/resources/ethernet/LwIP/arch \ -I$(KERNEL_ROOT)/resources/include \ -I$(BSP_ROOT)/include \ -I$(BSP_ROOT)/xip # From 56fbb14dad408a2d5d959fa7d54c585d532ac027 Mon Sep 17 00:00:00 2001 From: Wang_Weigen Date: Thu, 24 Mar 2022 17:21:14 +0800 Subject: [PATCH 5/5] replace file 'fsl_phy.c' to support LAN8720a --- .../third_party_driver/ethernet/Makefile | 2 +- .../ethernet/{ksz8081 => lan8720}/Makefile | 0 .../ethernet/{ksz8081 => lan8720}/fsl_phy.c | 96 +++++++++---------- .../ethernet/{ksz8081 => lan8720}/fsl_phy.h | 74 ++++++++------ Ubiquitous/XiZi/path_kernel.mk | 2 +- 5 files changed, 95 insertions(+), 79 deletions(-) rename Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/{ksz8081 => lan8720}/Makefile (100%) rename Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/{ksz8081 => lan8720}/fsl_phy.c (71%) mode change 100755 => 100644 rename Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/{ksz8081 => lan8720}/fsl_phy.h (72%) mode change 100755 => 100644 diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile index 14be72829..65f5adc78 100755 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/Makefile @@ -1,3 +1,3 @@ SRC_FILES := enet_ethernetif.c enet_ethernetif_kinetis.c fsl_enet.c -SRC_DIR := ksz8081 +SRC_DIR := lan8720 include $(KERNEL_ROOT)/compiler.mk \ No newline at end of file diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/Makefile b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/Makefile similarity index 100% rename from Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/Makefile rename to Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/Makefile diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/fsl_phy.c old mode 100755 new mode 100644 similarity index 71% rename from Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c rename to Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/fsl_phy.c index 7f99f8216..1017aa038 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.c +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/fsl_phy.c @@ -1,28 +1,44 @@ /* + * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. - * Copyright 2016-2018 NXP + * Copyright 2016-2017 NXP * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: * - * SPDX-License-Identifier: BSD-3-Clause + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. */ -/** - * @file fsl_phy.c - * @brief phy drivers for ksz8081 - * @version 1.0 - * @author AIIT XUOS Lab - * @date 2021.11.11 - */ - -#include "lwipopts.h" #include "fsl_phy.h" - /******************************************************************************* * Definitions ******************************************************************************/ /*! @brief Defines the timeout macro. */ -#define PHY_TIMEOUT_COUNT 100000 +#define PHY_TIMEOUT_COUNT 0x3FFFFFFU /******************************************************************************* * Prototypes @@ -52,12 +68,11 @@ extern clock_ip_name_t s_enetClock[FSL_FEATURE_SOC_ENET_COUNT]; status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) { uint32_t bssReg; - uint32_t counter = PHY_TIMEOUT_COUNT; - uint32_t idReg = 0; - status_t result = kStatus_Success; + uint32_t counter = PHY_TIMEOUT_COUNT; + uint32_t idReg = 0; + status_t result = kStatus_Success; uint32_t instance = ENET_GetInstance(base); uint32_t timeDelay; - uint32_t ctlReg = 0; #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) /* Set SMI first. */ @@ -69,7 +84,7 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) while ((idReg != PHY_CONTROL_ID1) && (counter != 0)) { PHY_Read(base, phyAddr, PHY_ID1_REG, &idReg); - counter--; + counter --; } if (!counter) @@ -79,44 +94,30 @@ status_t PHY_Init(ENET_Type *base, uint32_t phyAddr, uint32_t srcClock_Hz) /* Reset PHY. */ counter = PHY_TIMEOUT_COUNT; - result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, PHY_BCTL_RESET_MASK); if (result == kStatus_Success) - { -#if defined(FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE) - uint32_t data = 0; - result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data); - if (result != kStatus_Success) - { - return result; - } - result = PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REFCLK_SELECT_MASK)); - if (result != kStatus_Success) - { - return result; - } -#endif /* FSL_FEATURE_PHYKSZ8081_USE_RMII50M_MODE */ - + { + /* Set the negotiation. */ result = PHY_Write(base, phyAddr, PHY_AUTONEG_ADVERTISE_REG, (PHY_100BASETX_FULLDUPLEX_MASK | PHY_100BASETX_HALFDUPLEX_MASK | PHY_10BASETX_FULLDUPLEX_MASK | PHY_10BASETX_HALFDUPLEX_MASK | 0x1U)); if (result == kStatus_Success) { - result = - PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); + result = PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, + (PHY_BCTL_AUTONEG_MASK | PHY_BCTL_RESTART_AUTONEG_MASK)); if (result == kStatus_Success) { /* Check auto negotiation complete. */ - while (counter--) + while (counter --) { result = PHY_Read(base, phyAddr, PHY_BASICSTATUS_REG, &bssReg); - if (result == kStatus_Success) + if ( result == kStatus_Success) { - PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg); - if (((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) && (ctlReg & PHY_LINK_READY_MASK)) + if ((bssReg & PHY_BSTATUS_AUTONEGCOMP_MASK) != 0) { /* Wait a moment for Phy status stable. */ - for (timeDelay = 0; timeDelay < PHY_TIMEOUT_COUNT; timeDelay++) + for (timeDelay = 0; timeDelay < PHY_TIMEOUT_COUNT; timeDelay ++) { __ASM("nop"); } @@ -219,17 +220,17 @@ status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, } else { - data = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; + data = PHY_BCTL_DUPLEX_MASK | PHY_BCTL_LOOP_MASK; } - return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, data); + return PHY_Write(base, phyAddr, PHY_BASICCONTROL_REG, data); } else { /* First read the current status in control register. */ - result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data); + result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &data); if (result == kStatus_Success) { - return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data | PHY_CTL2_REMOTELOOP_MASK)); + return PHY_Write(base, phyAddr, PHY_CONTROL1_REG, (data | PHY_CTL1_REMOTELOOP_MASK)); } } } @@ -249,10 +250,10 @@ status_t PHY_EnableLoopback(ENET_Type *base, uint32_t phyAddr, phy_loop_t mode, else { /* First read the current status in control one register. */ - result = PHY_Read(base, phyAddr, PHY_CONTROL2_REG, &data); + result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &data); if (result == kStatus_Success) { - return PHY_Write(base, phyAddr, PHY_CONTROL2_REG, (data & ~PHY_CTL2_REMOTELOOP_MASK)); + return PHY_Write(base, phyAddr, PHY_CONTROL1_REG, (data & ~PHY_CTL1_REMOTELOOP_MASK)); } } } @@ -291,7 +292,6 @@ status_t PHY_GetLinkSpeedDuplex(ENET_Type *base, uint32_t phyAddr, phy_speed_t * status_t result = kStatus_Success; uint32_t data, ctlReg; - /* Read the control two register. */ result = PHY_Read(base, phyAddr, PHY_CONTROL1_REG, &ctlReg); if (result == kStatus_Success) diff --git a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/fsl_phy.h old mode 100755 new mode 100644 similarity index 72% rename from Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h rename to Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/fsl_phy.h index 3f0e905fa..3e2a93cb1 --- a/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/ksz8081/fsl_phy.h +++ b/Ubiquitous/XiZi/board/xidatong/third_party_driver/ethernet/lan8720/fsl_phy.h @@ -1,19 +1,36 @@ /* + * The Clear BSD License * Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted (subject to the limitations in the disclaimer below) provided + * that the following conditions are met: * - * SPDX-License-Identifier: BSD-3-Clause + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o 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. + * + * o Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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. */ - -/** - * @file fsl_phy.h - * @brief phy drivers for ksz8081 - * @version 1.0 - * @author AIIT XUOS Lab - * @date 2021.11.11 - */ - #ifndef _FSL_PHY_H_ #define _FSL_PHY_H_ @@ -37,10 +54,9 @@ #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_CONTROL1_REG 0x1EU /*!< The PHY control one register. */ -#define PHY_CONTROL2_REG 0x1FU /*!< The PHY control two register. */ +#define PHY_CONTROL1_REG 0x1FU /*!< The PHY control one register. */ -#define PHY_CONTROL_ID1 0x22U /*!< The PHY ID1*/ +#define PHY_CONTROL_ID1 0x07U /*!< The PHY ID1*/ /*! @brief Defines the mask flag in basic control register. */ #define PHY_BCTL_DUPLEX_MASK 0x0100U /*!< The PHY duplex bit mask. */ @@ -49,20 +65,20 @@ #define PHY_BCTL_SPEED_MASK 0x2000U /*!< The PHY speed bit mask. */ #define PHY_BCTL_LOOP_MASK 0x4000U /*!< The PHY loop bit mask. */ #define PHY_BCTL_RESET_MASK 0x8000U /*!< The PHY reset bit mask. */ -#define PHY_BCTL_SPEED_100M_MASK 0x2000U /*!< The PHY 100M speed mask. */ +#define PHY_BCTL_SPEED_100M_MASK 0x2000U /*!< The PHY 100M speed mask. */ /*!@brief Defines the mask flag of operation mode in control two register*/ -#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_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 0x0004U /*!< The PHY 10M half duplex mask. */ +#define PHY_CTL1_100HALFDUPLEX_MASK 0x0008U /*!< The PHY 100M half duplex mask. */ +#define PHY_CTL1_10FULLDUPLEX_MASK 0x0014U /*!< The PHY 10M full duplex mask. */ +#define PHY_CTL1_100FULLDUPLEX_MASK 0x0018U /*!< The PHY 100M full duplex mask. */ +#define PHY_CTL1_SPEEDUPLX_MASK 0x001CU /*!< 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_CTL1_LINKUP_MASK 0x100U /*!< The PHY link up. */ #define PHY_LINK_READY_MASK (PHY_CTL1_ENERGYDETECT_MASK | PHY_CTL1_LINKUP_MASK) - + /*! @brief Defines the mask flag in basic status register. */ #define PHY_BSTATUS_LINKSTATUS_MASK 0x0004U /*!< The PHY link status mask. */ #define PHY_BSTATUS_AUTONEGABLE_MASK 0x0008U /*!< The PHY auto-negotiation ability mask. */ @@ -78,8 +94,8 @@ /*! @brief Defines the PHY status. */ enum _phy_status { - kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 1), /*!< ENET PHY SMI visit timeout. */ - kStatus_PHY_AutoNegotiateFail = MAKE_STATUS(kStatusGroup_PHY, 2) /*!< ENET PHY AutoNegotiate Fail. */ + kStatus_PHY_SMIVisitTimeout = MAKE_STATUS(kStatusGroup_PHY, 1), /*!< ENET PHY SMI visit timeout. */ + kStatus_PHY_AutoNegotiateFail = MAKE_STATUS(kStatusGroup_PHY, 2) /*!< ENET PHY AutoNegotiate Fail. */ }; /*! @brief Defines the PHY link speed. This is align with the speed for ENET MAC. */ @@ -112,16 +128,16 @@ extern "C" { #endif /*! - * @name PHY Driver - * @{ - */ + * @name PHY Driver + * @{ + */ /*! * @brief Initializes PHY. * * This function initialize the SMI interface and initialize PHY. * The SMI is the MII management interface between PHY and MAC, which should be - * firstly initialized before any other operation for PHY. The PHY initialize with auto-negotiation. + * firstly initialized before any other operation for PHY. The PHY initialize with auto-negotiation. * * @param base ENET peripheral base address. * @param phyAddr The PHY address. diff --git a/Ubiquitous/XiZi/path_kernel.mk b/Ubiquitous/XiZi/path_kernel.mk index 3696e2a4b..3b6f53047 100755 --- a/Ubiquitous/XiZi/path_kernel.mk +++ b/Ubiquitous/XiZi/path_kernel.mk @@ -14,7 +14,7 @@ KERNELPATHS :=-I$(BSP_ROOT) \ -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/osa \ -I$(BSP_ROOT)/third_party_driver/usb/nxp_usb_driver/phy \ -I$(BSP_ROOT)/third_party_driver/ethernet \ - -I$(BSP_ROOT)/third_party_driver/ethernet/ksz8081 \ + -I$(BSP_ROOT)/third_party_driver/ethernet/lan8720 \ -I$(BSP_ROOT)/third_party_driver/MIMXRT1052 \ -I$(BSP_ROOT)/third_party_driver/MIMXRT1052/drivers \ -I$(BSP_ROOT)/third_party_driver/CMSIS/Include \